feat: 完善稳定性并重构潜影盒安全机制

This commit is contained in:
2026-08-02 03:36:19 +08:00
parent d9b1312e0c
commit 92ef7f6030
35 changed files with 1167 additions and 229 deletions
@@ -1,7 +1,6 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
@@ -16,6 +15,8 @@ import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.ArrayList;
import java.util.List;
@@ -25,8 +26,6 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
private static final int MENU_SIZE = 36;
private static final int[] DIVIDER_SLOTS = {4, 13, 22, 31};
private static boolean listenerRegistered = false;
private final NamespacedKey blockKey;
private static final class BlocksMenuHolder implements InventoryHolder {
@@ -45,10 +44,7 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
public BlocksMenuCommand() {
super("essentialsc.command.blocks");
addConfigDefaults();
if (!listenerRegistered) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
listenerRegistered = true;
}
plugin.getServer().getPluginManager().registerEvents(this, plugin);
this.blockKey = new NamespacedKey(plugin, "block_key");
}
@@ -170,8 +166,10 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
ItemStack item = new ItemStack(menuItem.material());
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(menuItem.name());
meta.setLore(menuItem.lore().isEmpty() ? null : menuItem.lore());
meta.displayName(legacyComponent(menuItem.name()));
meta.lore(menuItem.lore().isEmpty() ? null : menuItem.lore().stream()
.map(this::legacyComponent)
.toList());
if (menuItem.commandKey() != null && !menuItem.commandKey().isBlank()) {
meta.getPersistentDataContainer().set(blockKey, PersistentDataType.STRING, menuItem.commandKey());
}
@@ -184,7 +182,7 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
ItemStack divider = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
ItemMeta meta = divider.getItemMeta();
if (meta != null) {
meta.setDisplayName(" ");
meta.displayName(Component.text(" "));
divider.setItemMeta(meta);
}
@@ -250,8 +248,8 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
}
}
private String translateColor(String text) {
return text == null ? "" : ChatColor.translateAlternateColorCodes('&', text);
private Component legacyComponent(String text) {
return LegacyComponentSerializer.legacySection().deserialize(text == null ? "" : text);
}
private void addConfigDefaults() {
@@ -176,8 +176,7 @@ public final class CommandRegistry {
}
}
public static void clearCache() {
COMMAND_CACHE.clear();
public static void clearInitializationFailures() {
UNAVAILABLE_COMMANDS.clear();
}
@@ -54,6 +54,11 @@ public class GlowCommand extends BaseCommand {
private boolean isPluginGlowEnabled(Player player) {
Byte value = player.getPersistentDataContainer().get(enabledKey, PersistentDataType.BYTE);
return value != null && value == (byte) 1;
boolean enabled = value != null && value == (byte) 1;
if (enabled && !player.isGlowing()) {
player.getPersistentDataContainer().remove(enabledKey);
return false;
}
return enabled;
}
}
@@ -1,6 +1,8 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Bukkit;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.Player;
import java.util.Map;
@@ -37,7 +39,8 @@ public class HealCommand extends BaseCommand {
}
private void healPlayer(Player player) {
player.setHealth(player.getMaxHealth());
AttributeInstance maxHealth = player.getAttribute(Attribute.MAX_HEALTH);
player.setHealth(maxHealth == null ? player.getHealth() : maxHealth.getValue());
player.setFoodLevel(20);
player.setSaturation(20f);
player.clearActivePotionEffects();
@@ -20,6 +20,17 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
super("essentialsc.command.help");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length > 0) {
if (sender instanceof Player player) {
return handleCommand(sender, player, args);
}
return executeConsole(sender, args);
}
return super.onCommand(sender, command, label, args);
}
@Override
protected boolean execute(Player player, String[] args) {
return handleCommand(player, player, args);
@@ -36,7 +47,7 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
EssentialsC.getLangManager().reload();
plugin.getFeatureConfigManager().reload();
plugin.getModuleManager().reload();
CommandRegistry.clearCache();
CommandRegistry.clearInitializationFailures();
plugin.reloadRuntimeModules();
sender.sendMessage(getLang().getPrefixedString("messages.config-reloaded"));
return true;
@@ -58,7 +69,7 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
EssentialsC.getLangManager().reload();
plugin.getFeatureConfigManager().reload();
plugin.getModuleManager().reload();
CommandRegistry.clearCache();
CommandRegistry.clearInitializationFailures();
plugin.reloadRuntimeModules();
sender.sendMessage(getLang().getPrefixedString("messages.config-reloaded"));
return true;
@@ -41,12 +41,18 @@ public class MaintenanceCommand extends BaseCommand implements TabCompleter {
switch (args[0].toLowerCase(Locale.ROOT)) {
case "on", "enable", "enabled" -> {
maintenanceManager.setEnabled(true);
if (maintenanceManager.setEnabled(true) == MaintenanceManager.OperationResult.SAVE_FAILED) {
sendSaveFailed(sender);
return true;
}
sender.sendMessage(getLang().getPrefixedString("maintenance.messages.enabled"));
return true;
}
case "off", "disable", "disabled" -> {
maintenanceManager.setEnabled(false);
if (maintenanceManager.setEnabled(false) == MaintenanceManager.OperationResult.SAVE_FAILED) {
sendSaveFailed(sender);
return true;
}
sender.sendMessage(getLang().getPrefixedString("maintenance.messages.disabled"));
return true;
}
@@ -62,7 +68,10 @@ public class MaintenanceCommand extends BaseCommand implements TabCompleter {
}
String target = args[1];
if (maintenanceManager.addWhitelistEntry(target)) {
MaintenanceManager.OperationResult result = maintenanceManager.addWhitelistEntry(target);
if (result == MaintenanceManager.OperationResult.SAVE_FAILED) {
sendSaveFailed(sender);
} else if (result == MaintenanceManager.OperationResult.SUCCESS) {
sender.sendMessage(getLang().getPrefixedString("maintenance.messages.whitelist-added",
Map.of("player", target)));
} else {
@@ -78,7 +87,10 @@ public class MaintenanceCommand extends BaseCommand implements TabCompleter {
}
String target = args[1];
if (maintenanceManager.removeWhitelistEntry(target)) {
MaintenanceManager.OperationResult result = maintenanceManager.removeWhitelistEntry(target);
if (result == MaintenanceManager.OperationResult.SAVE_FAILED) {
sendSaveFailed(sender);
} else if (result == MaintenanceManager.OperationResult.SUCCESS) {
sender.sendMessage(getLang().getPrefixedString("maintenance.messages.whitelist-removed",
Map.of("player", target)));
} else {
@@ -123,6 +135,10 @@ public class MaintenanceCommand extends BaseCommand implements TabCompleter {
)));
}
private void sendSaveFailed(CommandSender sender) {
sender.sendMessage(getLang().getPrefixedString("maintenance.messages.save-failed"));
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission(getPermission())) {
@@ -8,6 +8,8 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.List;
import java.util.Map;
@@ -52,12 +54,12 @@ public class MobDropCommand extends BaseCommand {
ItemStack endermanItem = new ItemStack(Material.ENDER_PEARL);
ItemMeta endermanMeta = endermanItem.getItemMeta();
if (endermanMeta != null) {
endermanMeta.setDisplayName(lang.getString("mobdrops-menu.enderman.name"));
endermanMeta.setLore(List.of(
endermanMeta.displayName(legacyComponent(lang.getString("mobdrops-menu.enderman.name")));
endermanMeta.lore(List.of(
lang.getString("mobdrops-menu.enderman.status", Map.of("status", status)),
"",
lang.getString("mobdrops-menu.enderman.toggle")
));
).stream().map(MobDropCommand::legacyComponent).toList());
endermanItem.setItemMeta(endermanMeta);
}
menu.setItem(ENDERMAN_SLOT, endermanItem);
@@ -65,7 +67,7 @@ public class MobDropCommand extends BaseCommand {
ItemStack glass = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
ItemMeta glassMeta = glass.getItemMeta();
if (glassMeta != null) {
glassMeta.setDisplayName(" ");
glassMeta.displayName(Component.text(" "));
glass.setItemMeta(glassMeta);
}
@@ -82,6 +84,10 @@ public class MobDropCommand extends BaseCommand {
return ENDERMAN_SLOT;
}
private static Component legacyComponent(String text) {
return LegacyComponentSerializer.legacySection().deserialize(text == null ? "" : text);
}
private void openMobDropMenu(Player player) {
openMobDropMenu(plugin, player);
}
@@ -56,6 +56,11 @@ public class NightVisionCommand extends BaseCommand {
private boolean isPluginNightVisionEnabled(Player player) {
Byte value = player.getPersistentDataContainer().get(enabledKey, PersistentDataType.BYTE);
return value != null && value == (byte) 1;
boolean enabled = value != null && value == (byte) 1;
if (enabled && !player.hasPotionEffect(PotionEffectType.NIGHT_VISION)) {
player.getPersistentDataContainer().remove(enabledKey);
return false;
}
return enabled;
}
}
@@ -21,6 +21,13 @@ public class SeenCommand extends BaseCommand {
return true;
}
Player onlineTarget = Bukkit.getPlayerExact(args[0]);
if (onlineTarget != null && VanishCommand.isVanished(onlineTarget)
&& !player.hasPermission(VanishCommand.SEE_PERMISSION)) {
player.sendMessage(getLang().getPrefixedString("messages.player-not-found", Map.of("player", args[0])));
return true;
}
OfflinePlayer target = Bukkit.getOfflinePlayer(args[0]);
if (!target.hasPlayedBefore() && !target.isOnline()) {
player.sendMessage(getLang().getPrefixedString("messages.player-not-found", Map.of("player", args[0])));
@@ -17,10 +17,13 @@ public final class TpIgnoreCommand extends BaseCommand {
return true;
}
boolean ignoring = manager.toggleIgnoringRequests(player);
player.sendMessage(getLang().getPrefixedComponent(ignoring
? "tpa.messages.ignore-enabled"
: "tpa.messages.ignore-disabled"));
TeleportRequestManager.ToggleIgnoreResult result = manager.toggleIgnoringRequests(player);
String messagePath = switch (result) {
case ENABLED -> "tpa.messages.ignore-enabled";
case DISABLED -> "tpa.messages.ignore-disabled";
case SAVE_FAILED -> "tpa.messages.ignore-save-failed";
};
player.sendMessage(getLang().getPrefixedComponent(messagePath));
return true;
}
}
@@ -27,14 +27,23 @@ public class VanishCommand extends BaseCommand {
if (vanishedPlayers.contains(uuid)) {
vanishedPlayers.remove(uuid);
if (!saveState(plugin)) {
vanishedPlayers.add(uuid);
player.sendMessage(getLang().getPrefixedString("messages.vanish-save-failed"));
return true;
}
showPlayerToAll(plugin, player);
player.sendMessage(getLang().getPrefixedString("messages.vanish-disabled"));
} else {
vanishedPlayers.add(uuid);
if (!saveState(plugin)) {
vanishedPlayers.remove(uuid);
player.sendMessage(getLang().getPrefixedString("messages.vanish-save-failed"));
return true;
}
hidePlayerFromAll(plugin, player);
player.sendMessage(getLang().getPrefixedString("messages.vanish-enabled"));
}
saveState(plugin);
return true;
}
@@ -111,7 +120,7 @@ public class VanishCommand extends BaseCommand {
return vanishedPlayers.contains(player.getUniqueId());
}
private static void saveState(EssentialsC plugin) {
private static boolean saveState(EssentialsC plugin) {
if (stateFile == null) {
stateFile = new File(plugin.getDataFolder(), "vanished-players.yml");
}
@@ -119,8 +128,10 @@ public class VanishCommand extends BaseCommand {
state.set("players", vanishedPlayers.stream().map(UUID::toString).sorted().toList());
try {
AtomicYamlWriter.save(state, stateFile);
return true;
} catch (Exception exception) {
plugin.getLogger().warning("保存 vanished-players.yml 失败: " + exception.getMessage());
return false;
}
}
}