From d0ec54cb49a34c4112464e1084580975bf044c78 Mon Sep 17 00:00:00 2001 From: Taah Date: Mon, 10 Aug 2026 02:40:11 -0700 Subject: [PATCH] Support attributed commands and stable world initialization --- .../java/dev/plex/api/command/CommandApi.java | 15 +++++ .../api/command/CommandExecutionIdentity.java | 51 ++++++++++++++++ .../dev/plex/api/impl/DefaultCommandApi.java | 14 +++++ .../java/dev/plex/command/ServerCommand.java | 4 +- .../plex/command/ServerCommandContext.java | 35 +++++++++-- .../dev/plex/command/impl/AdminChatCMD.java | 4 +- .../dev/plex/command/impl/AdventureCMD.java | 2 +- .../java/dev/plex/command/impl/BanCMD.java | 2 +- .../dev/plex/command/impl/BlockEditCMD.java | 8 +-- .../dev/plex/command/impl/ConsoleSayCMD.java | 2 +- .../dev/plex/command/impl/CreativeCMD.java | 2 +- .../dev/plex/command/impl/EntityWipeCMD.java | 4 +- .../java/dev/plex/command/impl/FreezeCMD.java | 2 +- .../java/dev/plex/command/impl/KickCMD.java | 2 +- .../java/dev/plex/command/impl/LockupCMD.java | 2 +- .../dev/plex/command/impl/MobPurgeCMD.java | 4 +- .../java/dev/plex/command/impl/MuteCMD.java | 2 +- .../java/dev/plex/command/impl/SayCMD.java | 2 +- .../java/dev/plex/command/impl/SmiteCMD.java | 4 +- .../dev/plex/command/impl/SpectatorCMD.java | 2 +- .../dev/plex/command/impl/SurvivalCMD.java | 2 +- .../dev/plex/command/impl/TempbanCMD.java | 2 +- .../dev/plex/command/impl/TempmuteCMD.java | 2 +- .../java/dev/plex/command/impl/ToggleCMD.java | 2 +- .../java/dev/plex/command/impl/UnbanCMD.java | 2 +- .../dev/plex/command/impl/UnfreezeCMD.java | 2 +- .../java/dev/plex/command/impl/UnmuteCMD.java | 2 +- .../main/java/dev/plex/player/PlexPlayer.java | 7 +++ .../dev/plex/world/WorldSpawnSignManager.java | 58 +++++++++++++++---- 29 files changed, 197 insertions(+), 45 deletions(-) create mode 100644 api/src/main/java/dev/plex/api/command/CommandExecutionIdentity.java diff --git a/api/src/main/java/dev/plex/api/command/CommandApi.java b/api/src/main/java/dev/plex/api/command/CommandApi.java index 12db83c..c856ef0 100644 --- a/api/src/main/java/dev/plex/api/command/CommandApi.java +++ b/api/src/main/java/dev/plex/api/command/CommandApi.java @@ -2,6 +2,9 @@ import dev.plex.command.PlexCommand; import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; +import net.kyori.adventure.text.Component; /** * Registers and unregisters Plex commands with the running platform. @@ -47,4 +50,16 @@ public interface CommandApi * after the active command lifecycle was built */ boolean requiresLifecycleReload(); + + /** + * Dispatches a console-capable command with a human-readable audit identity. + * The command must be invoked from the server's global command thread. + * + * @param identityId UUID exposed as the command actor + * @param identityName name exposed by Plex command contexts + * @param command command line without a leading slash + * @param feedback receiver for command feedback + * @return whether the command was accepted by the dispatcher + */ + boolean dispatchAsConsole(UUID identityId, String identityName, String command, Consumer feedback); } diff --git a/api/src/main/java/dev/plex/api/command/CommandExecutionIdentity.java b/api/src/main/java/dev/plex/api/command/CommandExecutionIdentity.java new file mode 100644 index 0000000..36bb95c --- /dev/null +++ b/api/src/main/java/dev/plex/api/command/CommandExecutionIdentity.java @@ -0,0 +1,51 @@ +package dev.plex.api.command; + +import java.util.UUID; +import java.util.function.Supplier; +import org.jetbrains.annotations.ApiStatus; + +/** Carries an attributed command name through a synchronous Plex command dispatch. */ +@ApiStatus.Internal +public final class CommandExecutionIdentity +{ + private static final ThreadLocal IDENTITY = new ThreadLocal<>(); + + private CommandExecutionIdentity() + { + } + + public static T call(UUID uniqueId, String name, Supplier action) + { + Identity previous = IDENTITY.get(); + IDENTITY.set(new Identity(uniqueId, name)); + try + { + return action.get(); + } + finally + { + if (previous == null) + { + IDENTITY.remove(); + } + else + { + IDENTITY.set(previous); + } + } + } + + public static String currentName(String fallback) + { + Identity identity = IDENTITY.get(); + return identity == null || identity.name() == null || identity.name().isBlank() ? fallback : identity.name(); + } + + public static UUID currentUniqueId() + { + Identity identity = IDENTITY.get(); + return identity == null ? null : identity.uniqueId(); + } + + private record Identity(UUID uniqueId, String name) { } +} diff --git a/server/src/main/java/dev/plex/api/impl/DefaultCommandApi.java b/server/src/main/java/dev/plex/api/impl/DefaultCommandApi.java index 1a1eb0f..7dd5541 100644 --- a/server/src/main/java/dev/plex/api/impl/DefaultCommandApi.java +++ b/server/src/main/java/dev/plex/api/impl/DefaultCommandApi.java @@ -2,8 +2,13 @@ import dev.plex.Plex; import dev.plex.api.command.CommandApi; +import dev.plex.api.command.CommandExecutionIdentity; import dev.plex.command.PlexCommand; import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; final class DefaultCommandApi implements CommandApi { @@ -47,4 +52,13 @@ public boolean requiresLifecycleReload() { return plugin.getCommandHandler() != null && plugin.getCommandHandler().requiresLifecycleReload(); } + + @Override + public boolean dispatchAsConsole(UUID identityId, String identityName, String command, Consumer feedback) + { + return CommandExecutionIdentity.call( + identityId, + identityName, + () -> Bukkit.dispatchCommand(Bukkit.createCommandSender(feedback), command)); + } } diff --git a/server/src/main/java/dev/plex/command/ServerCommand.java b/server/src/main/java/dev/plex/command/ServerCommand.java index e28bcab..3cbfb8c 100644 --- a/server/src/main/java/dev/plex/command/ServerCommand.java +++ b/server/src/main/java/dev/plex/command/ServerCommand.java @@ -260,7 +260,7 @@ private boolean canUse(CommandSourceStack source) return false; } - if (commandSource == RequiredCommandSource.IN_GAME && sender instanceof ConsoleCommandSender) + if (commandSource == RequiredCommandSource.IN_GAME && !(sender instanceof Player)) { return false; } @@ -319,7 +319,7 @@ private boolean validateSourceAndPermission(CommandSender sender, ServerCommandC return false; } - if (commandSource == RequiredCommandSource.IN_GAME && sender instanceof ConsoleCommandSender) + if (commandSource == RequiredCommandSource.IN_GAME && context.isConsole()) { context.send(sender, context.messageComponent("noPermissionConsole")); return false; diff --git a/server/src/main/java/dev/plex/command/ServerCommandContext.java b/server/src/main/java/dev/plex/command/ServerCommandContext.java index 64d8c66..e9468c1 100644 --- a/server/src/main/java/dev/plex/command/ServerCommandContext.java +++ b/server/src/main/java/dev/plex/command/ServerCommandContext.java @@ -2,6 +2,7 @@ import com.mojang.brigadier.context.CommandContext; import dev.plex.Plex; +import dev.plex.api.command.CommandExecutionIdentity; import dev.plex.command.exception.CommandFailException; import dev.plex.command.exception.ConsoleMustDefinePlayerException; import dev.plex.command.exception.ConsoleOnlyException; @@ -32,6 +33,8 @@ public final class ServerCommandContext private final PlexCommand command; private final CommandContext brigadierContext; private final CommandSender sender; + private final String senderName; + private final UUID senderUuid; private final Player player; private final String[] args; @@ -41,6 +44,10 @@ public final class ServerCommandContext this.command = command; this.brigadierContext = brigadierContext; this.sender = brigadierContext.getSource().getSender(); + this.senderName = CommandExecutionIdentity.currentName(sender.getName()); + this.senderUuid = sender instanceof Player playerSender + ? playerSender.getUniqueId() + : CommandExecutionIdentity.currentUniqueId(); this.player = sender instanceof Player playerSender ? playerSender : null; this.args = args; } @@ -85,6 +92,26 @@ public CommandSender sender() return sender; } + /** + * Returns the attributed sender name for messages and audit logs. + * + * @return attributed sender name + */ + public String senderName() + { + return senderName; + } + + /** + * Returns the attributed sender UUID, if available. + * + * @return attributed sender UUID, or {@code null} + */ + public @Nullable UUID senderUuid() + { + return senderUuid; + } + /** * Returns the player sender, if this command was run by a player. * @@ -131,7 +158,7 @@ public boolean checkPermission(CommandSender sender, String permission) public boolean silentCheckPermission(CommandSender sender, String permission) { - PlexLog.debug("Checking {0} with {1}", sender.getName(), permission); + PlexLog.debug("Checking {0} with {1}", senderName, permission); if (!isConsole(sender)) { return silentCheckPermission((Player)sender, permission); @@ -155,11 +182,11 @@ public boolean silentCheckPermission(Player player, String permission) public @Nullable UUID getUUID(CommandSender sender) { - if (!(sender instanceof Player player)) + if (sender instanceof Player player) { - return null; + return player.getUniqueId(); } - return player.getUniqueId(); + return sender == this.sender ? senderUuid : null; } public boolean isConsole(CommandSender sender) diff --git a/server/src/main/java/dev/plex/command/impl/AdminChatCMD.java b/server/src/main/java/dev/plex/command/impl/AdminChatCMD.java index 5284bb4..095e769 100644 --- a/server/src/main/java/dev/plex/command/impl/AdminChatCMD.java +++ b/server/src/main/java/dev/plex/command/impl/AdminChatCMD.java @@ -82,8 +82,8 @@ protected Component execute(@NotNull ServerCommandContext context) } Component eventMessage = staffChatEvent.getMessage(); String serializedMessage = SafeMiniMessage.mmSerialize(eventMessage); - plugin.getServer().getConsoleSender().sendMessage(context.messageComponent("adminChatFormat", sender.getName(), prefix, serializedMessage)); - MessageUtil.sendStaffChat(plugin, sender, eventMessage, PlexUtils.adminChat(sender.getName(), prefix, serializedMessage).toArray(UUID[]::new)); + plugin.getServer().getConsoleSender().sendMessage(context.messageComponent("adminChatFormat", context.senderName(), prefix, serializedMessage)); + MessageUtil.sendStaffChat(plugin, sender, eventMessage, PlexUtils.adminChat(context.senderName(), prefix, serializedMessage).toArray(UUID[]::new)); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/AdventureCMD.java b/server/src/main/java/dev/plex/command/impl/AdventureCMD.java index 8983146..dee7755 100644 --- a/server/src/main/java/dev/plex/command/impl/AdventureCMD.java +++ b/server/src/main/java/dev/plex/command/impl/AdventureCMD.java @@ -60,7 +60,7 @@ protected Component execute(@NotNull ServerCommandContext context) targetPlayer.setGameMode(GameMode.ADVENTURE); context.messageComponent("gameModeSetTo", "adventure"); } - PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", sender.getName(), "adventure")); + PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", context.senderName(), "adventure")); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/BanCMD.java b/server/src/main/java/dev/plex/command/impl/BanCMD.java index 843c295..d938406 100644 --- a/server/src/main/java/dev/plex/command/impl/BanCMD.java +++ b/server/src/main/java/dev/plex/command/impl/BanCMD.java @@ -103,7 +103,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(true); punishment.setIp(plexPlayer.getIps().getLast()); plugin.getPunishmentManager().punish(plexPlayer, punishment); - PlexUtils.broadcast(context.messageComponent("banningPlayer", sender.getName(), plexPlayer.getName())); + PlexUtils.broadcast(context.messageComponent("banningPlayer", context.senderName(), plexPlayer.getName())); if (player != null) { plugin.getApi().scheduler().runEntity(player, () -> BungeeUtil.kickPlayer(plugin, player, Punishment.generateBanMessage(punishment, plugin.config.getString("banning.ban_url"), plugin.getPlayerNameResolver()))); diff --git a/server/src/main/java/dev/plex/command/impl/BlockEditCMD.java b/server/src/main/java/dev/plex/command/impl/BlockEditCMD.java index b2a1ade..e2e0388 100644 --- a/server/src/main/java/dev/plex/command/impl/BlockEditCMD.java +++ b/server/src/main/java/dev/plex/command/impl/BlockEditCMD.java @@ -70,7 +70,7 @@ protected Component execute(@NotNull ServerCommandContext context) } else if (args[0].equalsIgnoreCase("purge")) { - PlexUtils.broadcast(context.messageComponent("unblockingEdits", sender.getName(), context.messageString("blockeditAllPlayers"))); + PlexUtils.broadcast(context.messageComponent("unblockingEdits", context.senderName(), context.messageString("blockeditAllPlayers"))); int count = 0; for (String player : BlockListener.blockedPlayers.stream().toList()) { @@ -84,7 +84,7 @@ else if (args[0].equalsIgnoreCase("purge")) } else if (args[0].equalsIgnoreCase("all")) { - PlexUtils.broadcast(context.messageComponent("blockingEdits", sender.getName(), context.messageString("blockeditAllNonAdmins"))); + PlexUtils.broadcast(context.messageComponent("blockingEdits", context.senderName(), context.messageString("blockeditAllNonAdmins"))); int count = 0; for (final Player player : Bukkit.getOnlinePlayers()) { @@ -106,14 +106,14 @@ else if (args[0].equalsIgnoreCase("all")) context.send(sender, context.messageComponent("higherRankThanYou")); return null; } - PlexUtils.broadcast(context.messageComponent("blockingEdits", sender.getName(), player.getName())); + PlexUtils.broadcast(context.messageComponent("blockingEdits", context.senderName(), player.getName())); BlockListener.blockedPlayers.add(player.getName()); context.send(player, context.messageComponent("editsModified", context.messageString("blockeditBlockedState"))); context.send(sender, context.messageComponent("editsBlocked", player.getName())); } else { - PlexUtils.broadcast(context.messageComponent("unblockingEdits", sender.getName(), player.getName())); + PlexUtils.broadcast(context.messageComponent("unblockingEdits", context.senderName(), player.getName())); BlockListener.blockedPlayers.remove(player.getName()); context.send(player, context.messageComponent("editsModified", context.messageString("blockeditUnblockedState"))); context.send(sender, context.messageComponent("editsUnblocked", player.getName())); diff --git a/server/src/main/java/dev/plex/command/impl/ConsoleSayCMD.java b/server/src/main/java/dev/plex/command/impl/ConsoleSayCMD.java index f00a768..7b2634c 100644 --- a/server/src/main/java/dev/plex/command/impl/ConsoleSayCMD.java +++ b/server/src/main/java/dev/plex/command/impl/ConsoleSayCMD.java @@ -45,7 +45,7 @@ protected Component execute(@NotNull ServerCommandContext context) return context.usage(); } - PlexUtils.broadcast(PlexUtils.messageComponent("consoleSayMessage", sender.getName(), PlexUtils.mmStripColor(StringUtils.join(args, " ")))); + PlexUtils.broadcast(PlexUtils.messageComponent("consoleSayMessage", context.senderName(), PlexUtils.mmStripColor(StringUtils.join(args, " ")))); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/CreativeCMD.java b/server/src/main/java/dev/plex/command/impl/CreativeCMD.java index 6d022c1..d5b7df1 100644 --- a/server/src/main/java/dev/plex/command/impl/CreativeCMD.java +++ b/server/src/main/java/dev/plex/command/impl/CreativeCMD.java @@ -63,7 +63,7 @@ protected Component execute(@NotNull ServerCommandContext context) targetPlayer.setGameMode(GameMode.CREATIVE); context.messageComponent("gameModeSetTo", "creative"); } - PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", sender.getName(), "creative")); + PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", context.senderName(), "creative")); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/EntityWipeCMD.java b/server/src/main/java/dev/plex/command/impl/EntityWipeCMD.java index f2e6912..8d78d83 100644 --- a/server/src/main/java/dev/plex/command/impl/EntityWipeCMD.java +++ b/server/src/main/java/dev/plex/command/impl/EntityWipeCMD.java @@ -127,7 +127,7 @@ protected Component execute(@NotNull ServerCommandContext context) if (useBlacklist) { - PlexUtils.broadcast(context.messageComponent("removedEntities", sender.getName(), entityCount)); + PlexUtils.broadcast(context.messageComponent("removedEntities", context.senderName(), entityCount)); } else { @@ -138,7 +138,7 @@ protected Component execute(@NotNull ServerCommandContext context) } String list = String.join(", ", entityCounts.keySet()); list = list.replaceAll("(, )(?!.*\1)", (list.indexOf(", ") == list.lastIndexOf(", ") ? "" : ",") + " and "); - PlexUtils.broadcast(context.messageComponent("removedEntitiesOfTypes", sender.getName(), entityCount, list)); + PlexUtils.broadcast(context.messageComponent("removedEntitiesOfTypes", context.senderName(), entityCount, list)); } return null; } diff --git a/server/src/main/java/dev/plex/command/impl/FreezeCMD.java b/server/src/main/java/dev/plex/command/impl/FreezeCMD.java index 620fe3d..fb221cf 100644 --- a/server/src/main/java/dev/plex/command/impl/FreezeCMD.java +++ b/server/src/main/java/dev/plex/command/impl/FreezeCMD.java @@ -65,7 +65,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(true); plugin.getPunishmentManager().punish(punishedPlayer, punishment); - PlexUtils.broadcast(context.messageComponent("frozePlayer", sender.getName(), player.getName())); + PlexUtils.broadcast(context.messageComponent("frozePlayer", context.senderName(), player.getName())); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/KickCMD.java b/server/src/main/java/dev/plex/command/impl/KickCMD.java index 098db83..bcfbc9b 100644 --- a/server/src/main/java/dev/plex/command/impl/KickCMD.java +++ b/server/src/main/java/dev/plex/command/impl/KickCMD.java @@ -81,7 +81,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(false); punishment.setIp(player.getAddress().getAddress().getHostAddress().trim()); plugin.getPunishmentManager().punish(plexPlayer, punishment); - PlexUtils.broadcast(context.messageComponent("kickedPlayer", sender.getName(), plexPlayer.getName())); + PlexUtils.broadcast(context.messageComponent("kickedPlayer", context.senderName(), plexPlayer.getName())); BungeeUtil.kickPlayer(plugin, player, Punishment.generateKickMessage(punishment, plugin.getPlayerNameResolver())); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/LockupCMD.java b/server/src/main/java/dev/plex/command/impl/LockupCMD.java index fb3b59a..fe7f762 100644 --- a/server/src/main/java/dev/plex/command/impl/LockupCMD.java +++ b/server/src/main/java/dev/plex/command/impl/LockupCMD.java @@ -49,7 +49,7 @@ protected Component execute(@NotNull ServerCommandContext context) { player.openInventory(player.getInventory()); } - PlexUtils.broadcast(context.messageComponent(punishedPlayer.isLockedUp() ? "lockedUpPlayer" : "unlockedPlayer", sender.getName(), player.getName())); + PlexUtils.broadcast(context.messageComponent(punishedPlayer.isLockedUp() ? "lockedUpPlayer" : "unlockedPlayer", context.senderName(), player.getName())); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/MobPurgeCMD.java b/server/src/main/java/dev/plex/command/impl/MobPurgeCMD.java index 24403f3..8d9f7be 100644 --- a/server/src/main/java/dev/plex/command/impl/MobPurgeCMD.java +++ b/server/src/main/java/dev/plex/command/impl/MobPurgeCMD.java @@ -80,12 +80,12 @@ protected Component execute(@NotNull ServerCommandContext context) int count = purgeMobs(type); if (type != null) { - PlexUtils.broadcast(context.messageComponent("removedEntitiesOfTypes", sender.getName(), count, mobName)); + PlexUtils.broadcast(context.messageComponent("removedEntitiesOfTypes", context.senderName(), count, mobName)); PlexLog.debug("All " + count + " of " + mobName + " were removed"); } else { - PlexUtils.broadcast(context.messageComponent("removedMobs", sender.getName(), count)); + PlexUtils.broadcast(context.messageComponent("removedMobs", context.senderName(), count)); PlexLog.debug("All " + count + " valid mobs were removed"); } sender.sendMessage(context.messageComponent("amountOfMobsRemoved", count, type != null ? mobName + multipleS(count) : context.messageString(count == 1 ? "mobSingular" : "mobPlural"))); diff --git a/server/src/main/java/dev/plex/command/impl/MuteCMD.java b/server/src/main/java/dev/plex/command/impl/MuteCMD.java index 22df2bb..2558c81 100644 --- a/server/src/main/java/dev/plex/command/impl/MuteCMD.java +++ b/server/src/main/java/dev/plex/command/impl/MuteCMD.java @@ -71,7 +71,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(true); plugin.getPunishmentManager().punish(punishedPlayer, punishment); - PlexUtils.broadcast(context.messageComponent("mutedPlayer", sender.getName(), player.getName())); + PlexUtils.broadcast(context.messageComponent("mutedPlayer", context.senderName(), player.getName())); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/SayCMD.java b/server/src/main/java/dev/plex/command/impl/SayCMD.java index 2ef3a47..b437d95 100644 --- a/server/src/main/java/dev/plex/command/impl/SayCMD.java +++ b/server/src/main/java/dev/plex/command/impl/SayCMD.java @@ -42,7 +42,7 @@ protected Component execute(@NotNull ServerCommandContext context) return context.usage(); } - PlexUtils.broadcast(PlexUtils.messageComponent("sayMessage", sender.getName(), PlexUtils.mmStripColor(StringUtils.join(args, " ")))); + PlexUtils.broadcast(PlexUtils.messageComponent("sayMessage", context.senderName(), PlexUtils.mmStripColor(StringUtils.join(args, " ")))); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/SmiteCMD.java b/server/src/main/java/dev/plex/command/impl/SmiteCMD.java index cfeafe2..4c99571 100644 --- a/server/src/main/java/dev/plex/command/impl/SmiteCMD.java +++ b/server/src/main/java/dev/plex/command/impl/SmiteCMD.java @@ -88,12 +88,12 @@ protected Component execute(@NotNull ServerCommandContext context) final Player player = context.getNonNullPlayer(args[0]); final PlexPlayer plexPlayer = context.getPlexPlayer(player); - Title title = Title.title(context.messageComponent("smiteTitleHeader"), context.messageComponent("smiteTitleMessage", reason, sender.getName())); + Title title = Title.title(context.messageComponent("smiteTitleHeader"), context.messageComponent("smiteTitleMessage", reason, context.senderName())); player.showTitle(title); if (!silent) { - PlexUtils.broadcast(context.messageComponent("smiteBroadcast", player.getName(), reason != null ? reason : context.messageString("noReasonProvided"), sender.getName())); + PlexUtils.broadcast(context.messageComponent("smiteBroadcast", player.getName(), reason != null ? reason : context.messageString("noReasonProvided"), context.senderName())); } else { diff --git a/server/src/main/java/dev/plex/command/impl/SpectatorCMD.java b/server/src/main/java/dev/plex/command/impl/SpectatorCMD.java index d8d55d3..96effef 100644 --- a/server/src/main/java/dev/plex/command/impl/SpectatorCMD.java +++ b/server/src/main/java/dev/plex/command/impl/SpectatorCMD.java @@ -61,7 +61,7 @@ protected Component execute(@NotNull ServerCommandContext context) targetPlayer.setGameMode(GameMode.SPECTATOR); context.messageComponent("gameModeSetTo", "spectator"); } - PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", sender.getName(), "spectator")); + PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", context.senderName(), "spectator")); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/SurvivalCMD.java b/server/src/main/java/dev/plex/command/impl/SurvivalCMD.java index bda59b9..8cc7c8c 100644 --- a/server/src/main/java/dev/plex/command/impl/SurvivalCMD.java +++ b/server/src/main/java/dev/plex/command/impl/SurvivalCMD.java @@ -61,7 +61,7 @@ protected Component execute(@NotNull ServerCommandContext context) targetPlayer.setGameMode(GameMode.SURVIVAL); context.send(targetPlayer, context.messageComponent("gameModeSetTo", "survival")); } - PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", sender.getName(), "survival")); + PlexUtils.broadcast(context.messageComponent("setEveryoneGameMode", context.senderName(), "survival")); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/TempbanCMD.java b/server/src/main/java/dev/plex/command/impl/TempbanCMD.java index 704e3dc..2c8e4ef 100644 --- a/server/src/main/java/dev/plex/command/impl/TempbanCMD.java +++ b/server/src/main/java/dev/plex/command/impl/TempbanCMD.java @@ -88,7 +88,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(true); punishment.setIp(target.getIps().getLast()); plugin.getPunishmentManager().punish(target, punishment); - PlexUtils.broadcast(context.messageComponent("banningPlayer", sender.getName(), target.getName())); + PlexUtils.broadcast(context.messageComponent("banningPlayer", context.senderName(), target.getName())); if (player != null) { plugin.getApi().scheduler().runEntity(player, () -> BungeeUtil.kickPlayer(plugin, player, Punishment.generateBanMessage(punishment, plugin.config.getString("banning.ban_url"), plugin.getPlayerNameResolver()))); diff --git a/server/src/main/java/dev/plex/command/impl/TempmuteCMD.java b/server/src/main/java/dev/plex/command/impl/TempmuteCMD.java index 5b296cb..360748a 100644 --- a/server/src/main/java/dev/plex/command/impl/TempmuteCMD.java +++ b/server/src/main/java/dev/plex/command/impl/TempmuteCMD.java @@ -98,7 +98,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(true); plugin.getPunishmentManager().punish(punishedPlayer, punishment); - PlexUtils.broadcast(context.messageComponent("tempMutedPlayer", sender.getName(), player.getName(), TimeUtils.formatRelativeTime(endDate))); + PlexUtils.broadcast(context.messageComponent("tempMutedPlayer", context.senderName(), player.getName(), TimeUtils.formatRelativeTime(endDate))); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/ToggleCMD.java b/server/src/main/java/dev/plex/command/impl/ToggleCMD.java index b226ca4..2a99857 100644 --- a/server/src/main/java/dev/plex/command/impl/ToggleCMD.java +++ b/server/src/main/java/dev/plex/command/impl/ToggleCMD.java @@ -73,7 +73,7 @@ protected Component execute(@NotNull ServerCommandContext context) } case "chat" -> { - PlexUtils.broadcast(PlexUtils.messageComponent("chatToggled", sender.getName(), context.messageString(plugin.toggles.getBoolean("chat") ? "stateOff" : "stateOn"))); + PlexUtils.broadcast(PlexUtils.messageComponent("chatToggled", context.senderName(), context.messageString(plugin.toggles.getBoolean("chat") ? "stateOff" : "stateOn"))); return toggle(context, "chat"); } default -> diff --git a/server/src/main/java/dev/plex/command/impl/UnbanCMD.java b/server/src/main/java/dev/plex/command/impl/UnbanCMD.java index fd6f376..a0c155d 100644 --- a/server/src/main/java/dev/plex/command/impl/UnbanCMD.java +++ b/server/src/main/java/dev/plex/command/impl/UnbanCMD.java @@ -62,7 +62,7 @@ protected Component execute(@NotNull ServerCommandContext context) return; } plugin.getPunishmentManager().unban(target.getUuid()); - PlexUtils.broadcast(context.messageComponent("unbanningPlayer", sender.getName(), target.getName())); + PlexUtils.broadcast(context.messageComponent("unbanningPlayer", context.senderName(), target.getName())); }); } return null; diff --git a/server/src/main/java/dev/plex/command/impl/UnfreezeCMD.java b/server/src/main/java/dev/plex/command/impl/UnfreezeCMD.java index 57b0d72..73f7b03 100644 --- a/server/src/main/java/dev/plex/command/impl/UnfreezeCMD.java +++ b/server/src/main/java/dev/plex/command/impl/UnfreezeCMD.java @@ -61,7 +61,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(false); plugin.getPunishmentRepository().updatePunishment(punishment.getType(), false, punishment.getPunished()); }); - PlexUtils.broadcast(context.messageComponent("unfrozePlayer", sender.getName(), punishedPlayer.getName())); + PlexUtils.broadcast(context.messageComponent("unfrozePlayer", context.senderName(), punishedPlayer.getName())); return null; } diff --git a/server/src/main/java/dev/plex/command/impl/UnmuteCMD.java b/server/src/main/java/dev/plex/command/impl/UnmuteCMD.java index 1eb3865..26e3b0a 100644 --- a/server/src/main/java/dev/plex/command/impl/UnmuteCMD.java +++ b/server/src/main/java/dev/plex/command/impl/UnmuteCMD.java @@ -62,7 +62,7 @@ protected Component execute(@NotNull ServerCommandContext context) punishment.setActive(false); plugin.getPunishmentRepository().updatePunishment(punishment.getType(), false, punishment.getPunished()); }); - PlexUtils.broadcast(context.messageComponent("unmutedPlayer", sender.getName(), punishedPlayer.getName())); + PlexUtils.broadcast(context.messageComponent("unmutedPlayer", context.senderName(), punishedPlayer.getName())); return null; } diff --git a/server/src/main/java/dev/plex/player/PlexPlayer.java b/server/src/main/java/dev/plex/player/PlexPlayer.java index b761da8..6d5aac5 100644 --- a/server/src/main/java/dev/plex/player/PlexPlayer.java +++ b/server/src/main/java/dev/plex/player/PlexPlayer.java @@ -8,6 +8,7 @@ import dev.plex.util.adapter.ZonedDateTimeAdapter; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -43,6 +44,7 @@ public class PlexPlayer private List ips = Lists.newArrayList(); + @Setter(AccessLevel.NONE) private List punishments = Lists.newArrayList(); private List notes = Lists.newArrayList(); @@ -72,6 +74,11 @@ public PlexPlayer(UUID playerUUID) this(playerUUID, true); } + public void setPunishments(List punishments) + { + this.punishments = new ArrayList<>(punishments); + } + public String displayName() { return PlainTextComponentSerializer.plainText().serialize(getPlayer().displayName()); diff --git a/server/src/main/java/dev/plex/world/WorldSpawnSignManager.java b/server/src/main/java/dev/plex/world/WorldSpawnSignManager.java index b2d8339..545a980 100644 --- a/server/src/main/java/dev/plex/world/WorldSpawnSignManager.java +++ b/server/src/main/java/dev/plex/world/WorldSpawnSignManager.java @@ -2,18 +2,25 @@ import dev.plex.Plex; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Bukkit; +import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; +import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Rotatable; import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; import org.bukkit.configuration.ConfigurationSection; public final class WorldSpawnSignManager @@ -149,6 +156,19 @@ private ProtectedSign locate(World world, String configKey) { signY = world.getHighestBlockYAt(SIGN_X, SIGN_Z) + 1; } + else + { + int highestSignY = signY; + while (signY > world.getMinHeight() + && world.getBlockAt(SIGN_X, signY - 1, SIGN_Z).getState() instanceof Sign) + { + signY--; + } + for (int y = signY + 1; y <= highestSignY; y++) + { + world.getBlockAt(SIGN_X, y, SIGN_Z).setType(Material.AIR, false); + } + } Block support = world.getBlockAt(SIGN_X, signY - 1, SIGN_Z); BlockData supportData = support.getType().isSolid() ? support.getBlockData().clone() @@ -184,27 +204,45 @@ private void restoreNow(World world, ProtectedSign protectedSign) block.setType(Material.OAK_SIGN, false); changed = true; } + if (block.getBlockData() instanceof Rotatable rotatable && rotatable.getRotation() != BlockFace.SOUTH) + { + rotatable.setRotation(BlockFace.SOUTH); + block.setBlockData(rotatable, false); + changed = true; + } BlockState state = block.getState(); if (!(state instanceof Sign sign)) { return; } - Component[] frontLines = { - Component.empty(), - Component.text(protectedSign.displayName()), - Component.text("- 0, 0 -"), - Component.empty() + String shortName = protectedSign.displayName() + .replaceFirst("(?i)\\s+world$", "") + .toUpperCase(Locale.ROOT); + Component[] lines = { + Component.text("✦ PLEX ✦", NamedTextColor.GOLD, TextDecoration.BOLD), + Component.text(shortName, NamedTextColor.YELLOW, TextDecoration.BOLD), + Component.text("WORLD SPAWN", NamedTextColor.GRAY), + Component.text("0 • 0", NamedTextColor.WHITE) }; - for (int line = 0; line < frontLines.length; line++) + for (Side side : Side.values()) { - if (!sign.getSide(Side.FRONT).line(line).equals(frontLines[line])) + SignSide signSide = sign.getSide(side); + for (int line = 0; line < lines.length; line++) + { + if (!signSide.line(line).equals(lines[line])) + { + signSide.line(line, lines[line]); + changed = true; + } + } + if (signSide.getColor() != DyeColor.YELLOW) { - sign.getSide(Side.FRONT).line(line, frontLines[line]); + signSide.setColor(DyeColor.YELLOW); changed = true; } - if (!sign.getSide(Side.BACK).line(line).equals(Component.empty())) + if (!signSide.isGlowingText()) { - sign.getSide(Side.BACK).line(line, Component.empty()); + signSide.setGlowingText(true); changed = true; } }