feat: 完成 Paper 26.1 适配并整理配置结构

This commit is contained in:
2026-04-24 04:37:57 +08:00
parent 33ca8abd2a
commit 00aa10a44e
39 changed files with 2345 additions and 849 deletions

View File

@@ -0,0 +1,16 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.entity.Player;
public class AdminCommand extends BaseCommand {
public AdminCommand() {
super("essentialsc.command.admin");
}
@Override
protected boolean execute(Player player, String[] args) {
plugin.getAdminModeManager().toggle(player);
return true;
}
}

View File

@@ -1,17 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class AnvilCommand extends BaseCommand {
public AnvilCommand() {
super("essentialsc.command.anvil");
}
@Override
protected boolean execute(Player player, String[] args) {
// 使用 Paper API 打开铁砧(标题跟随客户端语言)
player.openAnvil(null, true);
playBlockShortcutSound(player, Material.ANVIL, Sound.BLOCK_ANVIL_USE);
return true;
}
}

View File

@@ -2,53 +2,84 @@ package cn.infstar.essentialsC.commands;
import cn.infstar.essentialsC.EssentialsC;
import cn.infstar.essentialsC.LangManager;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundGroup;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Map;
public abstract class BaseCommand implements CommandExecutor {
protected String permission;
protected static cn.infstar.essentialsC.EssentialsC plugin;
protected static EssentialsC plugin;
public BaseCommand(String permission) {
this.permission = permission;
if (plugin == null) {
plugin = cn.infstar.essentialsC.EssentialsC.getPlugin(cn.infstar.essentialsC.EssentialsC.class);
plugin = EssentialsC.getPlugin(EssentialsC.class);
}
}
public String getPermission() {
return permission;
}
/**
* 获取语言管理器
*/
protected LangManager getLang() {
return EssentialsC.getLangManager();
}
protected void playBlockShortcutSound(Player player, Material material, Sound fallbackSound) {
Sound sound = resolvePlaceSound(material);
if (sound == null) {
sound = fallbackSound;
}
if (sound != null) {
player.playSound(player.getLocation(), sound, 1.0F, 1.0F);
}
}
protected void playShortcutSound(Player player, Sound sound) {
if (sound != null) {
player.playSound(player.getLocation(), sound, 1.0F, 1.0F);
}
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player player) {
if (!player.hasPermission(permission)) {
String message = getLang().getString("messages.no-permission",
java.util.Map.of("permission", permission));
player.sendMessage(message);
player.sendMessage(getLang().getPrefixedString("messages.no-permission",
Map.of("permission", permission)));
return true;
}
return execute(player, args);
} else {
return executeConsole(sender, args);
}
return executeConsole(sender, args);
}
protected abstract boolean execute(Player player, String[] args);
protected boolean executeConsole(CommandSender sender, String[] args) {
sender.sendMessage(getLang().getString("messages.player-only"));
sender.sendMessage(getLang().getPrefixedString("messages.player-only"));
return true;
}
private Sound resolvePlaceSound(Material material) {
if (material == null || !material.isBlock()) {
return null;
}
try {
SoundGroup soundGroup = material.createBlockData().getSoundGroup();
return soundGroup.getPlaceSound();
} catch (IllegalArgumentException ignored) {
return null;
}
}
}

View File

@@ -8,17 +8,21 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
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;
@@ -38,6 +42,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;
@@ -52,14 +57,70 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
}
private void openMenu(Player player) {
String title = plugin.getConfig().getString("blocks-menu.title", "&6&lEssentialsC &8- &e&lBlocks Menu");
Inventory menu = new BlocksMenuHolder(translateColor(title)).getInventory();
Inventory menu = new BlocksMenuHolder(getLang().getString("blocks-menu.title")).getInventory();
var sectionsConfig = plugin.getConfig().getConfigurationSection("blocks-menu.sections");
if (sectionsConfig != null) {
int visibleSections = renderSections(menu, player, sectionsConfig);
if (visibleSections > 1) {
renderDivider(menu);
}
if (menu.isEmpty()) {
player.sendMessage(getLang().getPrefixedString("messages.blocks-menu-empty"));
return;
}
player.openInventory(menu);
return;
}
var itemsConfig = plugin.getConfig().getConfigurationSection("blocks-menu.items");
if (itemsConfig == null) {
return;
}
renderItems(menu, player, itemsConfig);
if (menu.isEmpty()) {
player.sendMessage(getLang().getPrefixedString("messages.blocks-menu-empty"));
return;
}
player.openInventory(menu);
}
private int renderSections(Inventory menu, Player player, org.bukkit.configuration.ConfigurationSection sectionsConfig) {
int visibleSections = 0;
for (String sectionKey : sectionsConfig.getKeys(false)) {
var section = sectionsConfig.getConfigurationSection(sectionKey);
if (section == null) {
continue;
}
var itemsConfig = section.getConfigurationSection("items");
if (itemsConfig == null) {
continue;
}
List<MenuItem> visibleItems = collectVisibleItems(player, itemsConfig);
if (visibleItems.isEmpty()) {
continue;
}
visibleSections++;
for (MenuItem item : visibleItems) {
addItem(menu, item);
}
}
return visibleSections;
}
private void renderItems(Inventory menu, Player player, org.bukkit.configuration.ConfigurationSection itemsConfig) {
for (MenuItem item : collectVisibleItems(player, itemsConfig)) {
addItem(menu, item);
}
}
private List<MenuItem> collectVisibleItems(Player player, org.bukkit.configuration.ConfigurationSection itemsConfig) {
List<MenuItem> items = new ArrayList<>();
for (String key : itemsConfig.getKeys(false)) {
var section = itemsConfig.getConfigurationSection(key);
if (section == null) {
@@ -67,37 +128,66 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
}
String permission = section.getString("permission");
if (permission != null && !player.hasPermission(permission)) {
if (permission != null && !permission.isBlank() && !player.hasPermission(permission)) {
continue;
}
int slot = section.getInt("slot");
Material material = Material.matchMaterial(section.getString("material", "STONE"));
if (material == null) {
material = Material.STONE;
String commandKey = section.getString("command", key);
if (!CommandRegistry.isAvailable(commandKey)) {
continue;
}
String name = translateColor(section.getString("name", "&fItem"));
List<String> lore = section.getStringList("lore").stream()
.map(this::translateColor)
.toList();
addItem(menu, slot, material, name, lore, key);
MenuItem item = createMenuItem(section, commandKey);
if (item != null) {
items.add(item);
}
}
player.openInventory(menu);
return items;
}
private void addItem(Inventory inv, int slot, Material material, String name, List<String> lore, String key) {
ItemStack item = new ItemStack(material);
private MenuItem createMenuItem(org.bukkit.configuration.ConfigurationSection section, String commandKey) {
int slot = section.getInt("slot", -1);
if (slot < 0 || slot >= MENU_SIZE) {
return null;
}
Material material = Material.matchMaterial(section.getString("material", "STONE"));
if (material == null) {
material = Material.STONE;
}
String name = getLang().getString("blocks-menu.items." + commandKey + ".name");
List<String> lore = getLang().getStringList("blocks-menu.items." + commandKey + ".lore");
return new MenuItem(slot, material, name, lore, commandKey);
}
private void addItem(Inventory inventory, MenuItem menuItem) {
ItemStack item = new ItemStack(menuItem.material());
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(name);
meta.setLore(lore);
meta.getPersistentDataContainer().set(this.blockKey, PersistentDataType.STRING, key);
meta.setDisplayName(menuItem.name());
meta.setLore(menuItem.lore().isEmpty() ? null : menuItem.lore());
if (menuItem.commandKey() != null && !menuItem.commandKey().isBlank()) {
meta.getPersistentDataContainer().set(blockKey, PersistentDataType.STRING, menuItem.commandKey());
}
item.setItemMeta(meta);
}
inv.setItem(slot, item);
inventory.setItem(menuItem.slot(), item);
}
private void renderDivider(Inventory inventory) {
ItemStack divider = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
ItemMeta meta = divider.getItemMeta();
if (meta != null) {
meta.setDisplayName(" ");
divider.setItemMeta(meta);
}
for (int slot : DIVIDER_SLOTS) {
if (inventory.getItem(slot) == null) {
inventory.setItem(slot, divider);
}
}
}
@EventHandler
@@ -105,44 +195,123 @@ public class BlocksMenuCommand extends BaseCommand implements Listener {
if (!(event.getView().getTopInventory().getHolder(false) instanceof BlocksMenuHolder)) {
return;
}
event.setCancelled(true);
if (!(event.getWhoClicked() instanceof Player player)) {
return;
}
if (event.getClickedInventory() != event.getView().getTopInventory()) {
return;
}
event.setCancelled(true);
ItemStack clicked = event.getCurrentItem();
if (clicked == null || !clicked.hasItemMeta()) {
return;
}
ItemMeta meta = clicked.getItemMeta();
String key = meta.getPersistentDataContainer().get(this.blockKey, PersistentDataType.STRING);
BaseCommand blockCommand = CommandRegistry.getCommand(key);
if (blockCommand != null) {
playBlockOpenSound(player, key);
blockCommand.execute(player, new String[0]);
String key = meta.getPersistentDataContainer().get(blockKey, PersistentDataType.STRING);
if (key == null || key.isBlank()) {
return;
}
BaseCommand blockCommand = CommandRegistry.getCommand(key);
if (blockCommand == null) {
return;
}
String permission = blockCommand.getPermission();
if (permission != null && !permission.isBlank() && !player.hasPermission(permission)) {
player.sendMessage(getLang().getPrefixedString("messages.no-permission",
Map.of("permission", permission)));
return;
}
blockCommand.execute(player, new String[0]);
}
private void playBlockOpenSound(Player player, String key) {
org.bukkit.Sound sound = switch (key) {
case "workbench" -> org.bukkit.Sound.BLOCK_WOOD_HIT;
case "anvil" -> org.bukkit.Sound.BLOCK_ANVIL_USE;
case "cartographytable" -> org.bukkit.Sound.UI_CARTOGRAPHY_TABLE_TAKE_RESULT;
case "grindstone" -> org.bukkit.Sound.BLOCK_GRINDSTONE_USE;
case "loom" -> org.bukkit.Sound.UI_LOOM_TAKE_RESULT;
case "smithingtable" -> org.bukkit.Sound.BLOCK_SMITHING_TABLE_USE;
case "stonecutter" -> org.bukkit.Sound.BLOCK_STONE_HIT;
case "enderchest" -> org.bukkit.Sound.BLOCK_ENDER_CHEST_OPEN;
default -> null;
};
@EventHandler
public void onMenuDrag(InventoryDragEvent event) {
if (!(event.getView().getTopInventory().getHolder(false) instanceof BlocksMenuHolder)) {
return;
}
if (sound != null) {
player.playSound(player.getLocation(), sound, 1.0f, 1.0f);
int topSize = event.getView().getTopInventory().getSize();
for (int rawSlot : event.getRawSlots()) {
if (rawSlot >= 0 && rawSlot < topSize) {
event.setCancelled(true);
return;
}
}
}
private String translateColor(String text) {
return text == null ? "" : ChatColor.translateAlternateColorCodes('&', text);
}
private void addConfigDefaults() {
plugin.getConfig().addDefault("blocks-menu.layout-version", 2);
addMenuItemDefaults("blocks-menu.sections.blocks.items.workbench", 10, "CRAFTING_TABLE",
"essentialsc.command.workbench", "workbench");
addMenuItemDefaults("blocks-menu.sections.blocks.items.enderchest", 11, "ENDER_CHEST",
"essentialsc.command.enderchest", "enderchest");
addMenuItemDefaults("blocks-menu.sections.blocks.items.anvil", 12, "ANVIL",
"essentialsc.command.anvil", "anvil");
addMenuItemDefaults("blocks-menu.sections.blocks.items.grindstone", 19, "GRINDSTONE",
"essentialsc.command.grindstone", "grindstone");
addMenuItemDefaults("blocks-menu.sections.blocks.items.smithingtable", 20, "SMITHING_TABLE",
"essentialsc.command.smithingtable", "smithingtable");
addMenuItemDefaults("blocks-menu.sections.blocks.items.stonecutter", 21, "STONECUTTER",
"essentialsc.command.stonecutter", "stonecutter");
addMenuItemDefaults("blocks-menu.sections.blocks.items.loom", 28, "LOOM",
"essentialsc.command.loom", "loom");
addMenuItemDefaults("blocks-menu.sections.blocks.items.cartographytable", 29, "CARTOGRAPHY_TABLE",
"essentialsc.command.cartographytable", "cartographytable");
addMenuItemDefaults("blocks-menu.sections.shortcuts.items.nightvision", 14, "TINTED_GLASS",
"essentialsc.command.nightvision", "nightvision");
addMenuItemDefaults("blocks-menu.sections.shortcuts.items.glow", 15, "GLOWSTONE",
"essentialsc.command.glow", "glow");
plugin.getConfig().options().copyDefaults(true);
migrateLayoutIfNeeded();
plugin.saveConfig();
}
private void migrateLayoutIfNeeded() {
boolean hasStoredLayoutVersion = plugin.getConfig().contains("blocks-menu.layout-version", true);
if (hasStoredLayoutVersion && plugin.getConfig().getInt("blocks-menu.layout-version", 0) >= 2) {
return;
}
applySlot("blocks", "workbench", 10);
applySlot("blocks", "enderchest", 11);
applySlot("blocks", "anvil", 12);
applySlot("blocks", "grindstone", 19);
applySlot("blocks", "smithingtable", 20);
applySlot("blocks", "stonecutter", 21);
applySlot("blocks", "loom", 28);
applySlot("blocks", "cartographytable", 29);
applySlot("shortcuts", "nightvision", 14);
applySlot("shortcuts", "glow", 15);
plugin.getConfig().set("blocks-menu.sections.blocks.title-item", null);
plugin.getConfig().set("blocks-menu.sections.shortcuts.title-item", null);
plugin.getConfig().set("blocks-menu.layout-version", 2);
}
private void applySlot(String section, String key, int slot) {
plugin.getConfig().set("blocks-menu.sections." + section + ".items." + key + ".slot", slot);
}
private void addMenuItemDefaults(String path, int slot, String material, String permission, String command) {
plugin.getConfig().addDefault(path + ".slot", slot);
plugin.getConfig().addDefault(path + ".material", material);
plugin.getConfig().addDefault(path + ".permission", permission);
plugin.getConfig().addDefault(path + ".command", command);
}
private record MenuItem(int slot, Material material, String name, List<String> lore, String commandKey) {
}
}

View File

@@ -1,17 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class CartographyTableCommand extends BaseCommand {
public CartographyTableCommand() {
super("essentialsc.command.cartographytable");
}
@Override
protected boolean execute(Player player, String[] args) {
// 使用 Paper API 打开制图台(标题跟随客户端语言)
player.openCartographyTable(null, true);
playBlockShortcutSound(player, Material.CARTOGRAPHY_TABLE, Sound.ENTITY_VILLAGER_WORK_CARTOGRAPHER);
return true;
}
}

View File

@@ -1,5 +1,8 @@
package cn.infstar.essentialsC.commands;
import cn.infstar.essentialsC.EssentialsC;
import cn.infstar.essentialsC.tpsbar.TpsBarService;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.Collections;
@@ -29,20 +32,32 @@ public final class CommandRegistry {
register("hat", "essentialsc.command.hat", "cn.infstar.essentialsC.commands.HatCommand");
register("suicide", "essentialsc.command.suicide", "cn.infstar.essentialsC.commands.SuicideCommand", "die");
register("fly", "essentialsc.command.fly", "cn.infstar.essentialsC.commands.FlyCommand");
register("nightvision", "essentialsc.command.nightvision", "cn.infstar.essentialsC.commands.NightVisionCommand", "nv");
register("glow", "essentialsc.command.glow", "cn.infstar.essentialsC.commands.GlowCommand");
register("heal", "essentialsc.command.heal", "cn.infstar.essentialsC.commands.HealCommand");
register("vanish", "essentialsc.command.vanish", "cn.infstar.essentialsC.commands.VanishCommand", "v");
register("seen", "essentialsc.command.seen", "cn.infstar.essentialsC.commands.SeenCommand", "info");
register("feed", "essentialsc.command.feed", "cn.infstar.essentialsC.commands.FeedCommand");
register("repair", "essentialsc.command.repair", "cn.infstar.essentialsC.commands.RepairCommand", "rep");
register("tpsbar", "essentialsc.command.tpsbar", "cn.infstar.essentialsC.commands.TpsBarCommand");
register("mobdrops", "essentialsc.mobdrops.enderman", "cn.infstar.essentialsC.commands.MobDropCommand");
registerSubCommand("admin", "essentialsc.command.admin", "cn.infstar.essentialsC.commands.AdminCommand");
}
private CommandRegistry() {
}
private static void register(String name, String permission, String className, String... aliases) {
register(name, permission, className, true, aliases);
}
private static void registerSubCommand(String name, String permission, String className, String... aliases) {
register(name, permission, className, false, aliases);
}
private static void register(String name, String permission, String className, boolean standalone, String... aliases) {
List<String> aliasList = List.of(aliases);
CommandSpec spec = new CommandSpec(name, permission, className, aliasList);
CommandSpec spec = new CommandSpec(name, permission, className, aliasList, standalone);
COMMANDS.put(name, spec);
ALIAS_TO_COMMAND.put(name, name);
for (String alias : aliasList) {
@@ -83,6 +98,9 @@ public final class CommandRegistry {
if (UNAVAILABLE_COMMANDS.contains(resolvedName)) {
return null;
}
if (isRuntimeDisabled(resolvedName)) {
return null;
}
CommandSpec spec = COMMANDS.get(resolvedName);
if (spec == null) {
@@ -106,6 +124,20 @@ public final class CommandRegistry {
}
}
public record CommandSpec(String name, String permission, String className, List<String> aliases) {
private static boolean isRuntimeDisabled(String resolvedName) {
if (!"tpsbar".equals(resolvedName)) {
return false;
}
try {
EssentialsC plugin = EssentialsC.getPlugin(EssentialsC.class);
TpsBarService tpsBarService = plugin.getTpsBarManager();
return tpsBarService == null || !tpsBarService.isPluginCommandEnabled();
} catch (IllegalStateException ignored) {
return false;
}
}
public record CommandSpec(String name, String permission, String className, List<String> aliases, boolean standalone) {
}
}

View File

@@ -1,23 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
/**
* 末影箱命令 - 参考 EssentialsX 实现
* 直接打开玩家的末影箱,确保数据安全
*/
public class EnderChestCommand extends BaseCommand {
public EnderChestCommand() {
super("essentialsc.command.enderchest");
}
@Override
protected boolean execute(Player player, String[] args) {
// 直接打开玩家的末影箱EssentialsX 方式)
// 优点100% 安全,不会吞物品或刷物品
// 缺点:标题显示为 "Ender Chest"(由客户端语言决定)
player.openInventory(player.getEnderChest());
playBlockShortcutSound(player, Material.ENDER_CHEST, Sound.BLOCK_ENDER_CHEST_OPEN);
return true;
}
}

View File

@@ -2,42 +2,40 @@ package cn.infstar.essentialsC.commands;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class FeedCommand extends BaseCommand {
public FeedCommand() {
super("essentialsc.command.feed");
}
@Override
protected boolean execute(@NotNull Player player, String[] args) {
protected boolean execute(Player player, String[] args) {
if (args.length == 0) {
// 喂饱自己
feedPlayer(player);
player.sendMessage(getLang().getString("messages.feed-self"));
} else {
// 检查是否有喂饱他人的权限
if (!player.hasPermission("essentialsc.command.feed.others")) {
player.sendMessage(getLang().getString("messages.no-permission-others"));
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
player.sendMessage(getLang().getString("messages.player-not-found", Map.of("player", args[0])));
return true;
}
feedPlayer(target);
player.sendMessage(getLang().getString("messages.feed-other", Map.of("player", target.getName())));
target.sendMessage(getLang().getString("messages.feed-by-other", Map.of("admin", player.getName())));
player.sendMessage(getLang().getPrefixedString("messages.feed-self"));
return true;
}
if (!player.hasPermission("essentialsc.command.feed.others")) {
player.sendMessage(getLang().getPrefixedString("messages.no-permission-others"));
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
player.sendMessage(getLang().getPrefixedString("messages.player-not-found", Map.of("player", args[0])));
return true;
}
feedPlayer(target);
player.sendMessage(getLang().getPrefixedString("messages.feed-other", Map.of("player", target.getName())));
target.sendMessage(getLang().getPrefixedString("messages.feed-by-other", Map.of("admin", player.getName())));
return true;
}
private void feedPlayer(Player player) {
player.setFoodLevel(20);
player.setSaturation(20f);

View File

@@ -15,11 +15,11 @@ public class FlyCommand extends BaseCommand {
if (currentFlyState) {
player.setAllowFlight(false);
player.setFlying(false);
player.sendMessage(getLang().getString("messages.fly-disabled"));
player.sendMessage(getLang().getPrefixedString("messages.fly-disabled"));
} else {
player.setAllowFlight(true);
player.setFlying(true);
player.sendMessage(getLang().getString("messages.fly-enabled"));
player.sendMessage(getLang().getPrefixedString("messages.fly-enabled"));
}
return true;

View File

@@ -0,0 +1,59 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
public class GlowCommand extends BaseCommand {
private final NamespacedKey enabledKey;
public GlowCommand() {
super("essentialsc.command.glow");
this.enabledKey = new NamespacedKey(plugin, "glow_enabled");
}
@Override
protected boolean execute(Player player, String[] args) {
boolean currentState = isPluginGlowEnabled(player);
Boolean targetState = resolveTargetState(currentState, args);
if (targetState == null) {
player.sendMessage(getLang().getPrefixedString("messages.glow-usage"));
return true;
}
if (targetState) {
player.setGlowing(true);
player.getPersistentDataContainer().set(enabledKey, PersistentDataType.BYTE, (byte) 1);
playShortcutSound(player, Sound.BLOCK_AMETHYST_BLOCK_CHIME);
player.sendMessage(getLang().getPrefixedString("messages.glow-enabled"));
} else {
if (currentState) {
player.setGlowing(false);
player.getPersistentDataContainer().remove(enabledKey);
}
playShortcutSound(player, Sound.BLOCK_AMETHYST_CLUSTER_FALL);
player.sendMessage(getLang().getPrefixedString("messages.glow-disabled"));
}
return true;
}
private Boolean resolveTargetState(boolean currentState, String[] args) {
if (args.length == 0) {
return !currentState;
}
return switch (args[0].toLowerCase()) {
case "on", "true", "enable", "enabled" -> true;
case "off", "false", "disable", "disabled" -> false;
case "toggle" -> !currentState;
default -> null;
};
}
private boolean isPluginGlowEnabled(Player player) {
Byte value = player.getPersistentDataContainer().get(enabledKey, PersistentDataType.BYTE);
return value != null && value == (byte) 1;
}
}

View File

@@ -1,17 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class GrindstoneCommand extends BaseCommand {
public GrindstoneCommand() {
super("essentialsc.command.grindstone");
}
@Override
protected boolean execute(Player player, String[] args) {
// 使用 Paper API 打开砂轮(标题跟随客户端语言)
player.openGrindstone(null, true);
playBlockShortcutSound(player, Material.GRINDSTONE, Sound.BLOCK_GRINDSTONE_USE);
return true;
}
}

View File

@@ -6,37 +6,27 @@ import org.bukkit.inventory.ItemStack;
import java.util.Map;
public class HatCommand extends BaseCommand {
public HatCommand() {
super("essentialsc.command.hat");
}
@Override
protected boolean execute(Player player, String[] args) {
ItemStack handItem = player.getInventory().getItemInMainHand();
if (handItem == null || handItem.isEmpty()) {
player.sendMessage(getLang().getString("messages.hat-no-item"));
player.sendMessage(getLang().getPrefixedString("messages.hat-no-item"));
return true;
}
ItemStack helmet = player.getInventory().getHelmet();
// 如果头盔栏有物品,先放回背包
if (helmet != null && !helmet.isEmpty()) {
player.getInventory().setHelmet(handItem);
player.getInventory().setItemInMainHand(helmet);
} else {
player.getInventory().setHelmet(handItem);
player.getInventory().setItemInMainHand(null);
}
player.getInventory().setHelmet(handItem);
player.getInventory().setItemInMainHand(helmet == null || helmet.isEmpty() ? null : helmet);
player.updateInventory();
String itemName = handItem.getType().toString();
String message = getLang().getString("messages.hat-success",
Map.of("item", itemName));
player.sendMessage(message);
player.sendMessage(getLang().getPrefixedString("messages.hat-success",
Map.of("item", handItem.getType().toString())));
return true;
}
}

View File

@@ -2,42 +2,40 @@ package cn.infstar.essentialsC.commands;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class HealCommand extends BaseCommand {
public HealCommand() {
super("essentialsc.command.heal");
}
@Override
protected boolean execute(@NotNull Player player, String[] args) {
protected boolean execute(Player player, String[] args) {
if (args.length == 0) {
// 治疗自己
healPlayer(player);
player.sendMessage(getLang().getString("messages.heal-self"));
} else {
// 检查是否有治疗他人的权限
if (!player.hasPermission("essentialsc.command.heal.others")) {
player.sendMessage(getLang().getString("messages.no-permission-others"));
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
player.sendMessage(getLang().getString("messages.player-not-found", Map.of("player", args[0])));
return true;
}
healPlayer(target);
player.sendMessage(getLang().getString("messages.heal-other", Map.of("player", target.getName())));
target.sendMessage(getLang().getString("messages.heal-by-other", Map.of("admin", player.getName())));
player.sendMessage(getLang().getPrefixedString("messages.heal-self"));
return true;
}
if (!player.hasPermission("essentialsc.command.heal.others")) {
player.sendMessage(getLang().getPrefixedString("messages.no-permission-others"));
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
player.sendMessage(getLang().getPrefixedString("messages.player-not-found", Map.of("player", args[0])));
return true;
}
healPlayer(target);
player.sendMessage(getLang().getPrefixedString("messages.heal-other", Map.of("player", target.getName())));
target.sendMessage(getLang().getPrefixedString("messages.heal-by-other", Map.of("admin", player.getName())));
return true;
}
private void healPlayer(Player player) {
player.setHealth(player.getMaxHealth());
player.setFoodLevel(20);

View File

@@ -2,12 +2,14 @@ package cn.infstar.essentialsC.commands;
import cn.infstar.essentialsC.EssentialsC;
import cn.infstar.essentialsC.LangManager;
import cn.infstar.essentialsC.tpsbar.TpsBarService;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -27,15 +29,19 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
protected boolean executeConsole(CommandSender sender, String[] args) {
if (args.length > 0 && args[0].equalsIgnoreCase("reload")) {
if (!sender.hasPermission("essentialsc.command.reload")) {
sender.sendMessage(getLang().getString("messages.no-permission"));
sendNoPermission(sender, "essentialsc.command.reload");
return true;
}
plugin.reloadConfig();
EssentialsC.getLangManager().reload();
sender.sendMessage(getLang().getString("prefix") + "Configuration reloaded.");
TpsBarService tpsBarService = plugin.getTpsBarManager();
if (tpsBarService != null) {
tpsBarService.reloadSettings();
}
sender.sendMessage(getLang().getPrefixedString("messages.config-reloaded"));
return true;
}
sender.sendMessage(getLang().getString("messages.player-only"));
sender.sendMessage(getLang().getPrefixedString("messages.player-only"));
return true;
}
@@ -45,12 +51,16 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
if (subCommand.equals("reload")) {
if (!sender.hasPermission("essentialsc.command.reload")) {
sender.sendMessage(getLang().getString("messages.no-permission"));
sendNoPermission(sender, "essentialsc.command.reload");
return true;
}
plugin.reloadConfig();
EssentialsC.getLangManager().reload();
sender.sendMessage(getLang().getString("prefix") + "Configuration reloaded.");
TpsBarService tpsBarService = plugin.getTpsBarManager();
if (tpsBarService != null) {
tpsBarService.reloadSettings();
}
sender.sendMessage(getLang().getPrefixedString("messages.config-reloaded"));
return true;
}
@@ -59,39 +69,38 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
if (actualCommand != null && targetCommand != null) {
String permission = CommandRegistry.getPermission(actualCommand);
if (permission != null && !player.hasPermission(permission)) {
player.sendMessage(getLang().getString("messages.no-permission"));
sendNoPermission(player, permission);
return true;
}
if (actualCommand.equals("seen")) {
if (args.length < 2) {
player.sendMessage(getLang().getString("prefix") + getLang().getString("messages.seen-usage-console"));
String[] forwardedArgs = Arrays.copyOfRange(args, 1, args.length);
if (actualCommand.equals("seen") && forwardedArgs.length == 0) {
player.sendMessage(getLang().getPrefixedString("messages.seen-usage-console"));
return true;
}
targetCommand.execute(player, new String[]{args[1]});
} else {
targetCommand.execute(player, new String[0]);
}
targetCommand.execute(player, forwardedArgs);
return true;
}
if (subCommand.equals("version") || subCommand.equals("v")) {
player.sendMessage(getLang().getString("prefix") + "EssentialsC v" + plugin.getDescription().getVersion());
player.sendMessage(getLang().getString("prefix") + "Running on Paper " + Bukkit.getVersion());
player.sendMessage(getLang().getPrefixedString("messages.version",
Map.of("version", plugin.getDescription().getVersion())));
player.sendMessage(getLang().getPrefixedString("messages.paper-version",
Map.of("version", Bukkit.getVersion())));
return true;
}
player.sendMessage(getLang().getString("prefix") + getLang().getString("messages.unknown-subcommand",
player.sendMessage(getLang().getPrefixedString("messages.unknown-subcommand",
Map.of("command", subCommand)));
player.sendMessage(getLang().getString("prefix") + getLang().getString("messages.help-usage"));
player.sendMessage(getLang().getPrefixedString("messages.help-usage"));
return true;
}
LangManager lang = getLang();
String version = plugin.getDescription().getVersion();
player.sendMessage(lang.getString("help.title"));
player.sendMessage(lang.getString("help.version", Map.of("version", version)));
sendPrefixed(player, lang.getString("help.title"));
sendPrefixed(player, lang.getString("help.version", Map.of("version", version)));
player.sendMessage("");
boolean hasBlockCommands = false;
@@ -131,8 +140,8 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
}
if (hasBlockCommands) {
player.sendMessage(lang.getString("help.section-blocks"));
player.sendMessage(blockCommands.toString().trim());
sendPrefixed(player, lang.getString("help.section-blocks"));
sendPrefixedLines(player, blockCommands.toString().trim());
player.sendMessage("");
}
@@ -151,6 +160,14 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
otherCommands.append(lang.getString("help.commands.fly")).append("\n");
hasOtherCommands = true;
}
if (CommandRegistry.isAvailable("nightvision") && player.hasPermission("essentialsc.command.nightvision")) {
otherCommands.append(lang.getString("help.commands.nightvision")).append("\n");
hasOtherCommands = true;
}
if (CommandRegistry.isAvailable("glow") && player.hasPermission("essentialsc.command.glow")) {
otherCommands.append(lang.getString("help.commands.glow")).append("\n");
hasOtherCommands = true;
}
if (CommandRegistry.isAvailable("heal") && player.hasPermission("essentialsc.command.heal")) {
otherCommands.append(lang.getString("help.commands.heal")).append("\n");
hasOtherCommands = true;
@@ -163,17 +180,40 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
otherCommands.append(lang.getString("help.commands.seen")).append("\n");
hasOtherCommands = true;
}
if (CommandRegistry.isAvailable("admin") && player.hasPermission("essentialsc.command.admin")) {
otherCommands.append(lang.getString("help.commands.admin")).append("\n");
hasOtherCommands = true;
}
if (CommandRegistry.isAvailable("tpsbar") && player.hasPermission("essentialsc.command.tpsbar")) {
otherCommands.append(lang.getString("help.commands.tpsbar")).append("\n");
hasOtherCommands = true;
}
if (hasOtherCommands) {
player.sendMessage(lang.getString("help.section-other"));
player.sendMessage(otherCommands.toString().trim());
sendPrefixed(player, lang.getString("help.section-other"));
sendPrefixedLines(player, otherCommands.toString().trim());
player.sendMessage("");
}
player.sendMessage(lang.getString("help.footer"));
sendPrefixed(player, lang.getString("help.footer"));
return true;
}
private void sendNoPermission(CommandSender sender, String permission) {
sender.sendMessage(getLang().getPrefixedString("messages.no-permission",
Map.of("permission", permission)));
}
private void sendPrefixed(CommandSender sender, String message) {
sender.sendMessage(message);
}
private void sendPrefixedLines(CommandSender sender, String message) {
for (String line : message.split("\\R")) {
sendPrefixed(sender, line);
}
}
private String getActualCommand(String alias) {
return CommandRegistry.resolveCommandName(alias);
}
@@ -207,6 +247,9 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
{"suicide", "essentialsc.command.suicide"},
{"die", "essentialsc.command.suicide"},
{"fly", "essentialsc.command.fly"},
{"nightvision", "essentialsc.command.nightvision"},
{"nv", "essentialsc.command.nightvision"},
{"glow", "essentialsc.command.glow"},
{"heal", "essentialsc.command.heal"},
{"vanish", "essentialsc.command.vanish"},
{"v", "essentialsc.command.vanish"},
@@ -215,7 +258,9 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
{"feed", "essentialsc.command.feed"},
{"repair", "essentialsc.command.repair"},
{"rep", "essentialsc.command.repair"},
{"tpsbar", "essentialsc.command.tpsbar"},
{"mobdrops", "essentialsc.mobdrops.enderman"},
{"admin", "essentialsc.command.admin"},
{"version", null},
{"help", null}
};
@@ -247,8 +292,38 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
}
return players;
}
if ((subCmd.equals("nightvision") || subCmd.equals("nv")) && sender.hasPermission("essentialsc.command.nightvision")) {
return completeToggleArgs(args[1]);
}
if (subCmd.equals("glow") && sender.hasPermission("essentialsc.command.glow")) {
return completeToggleArgs(args[1]);
}
if (subCmd.equals("tpsbar") && sender.hasPermission("essentialsc.command.tpsbar.others")) {
List<String> players = new ArrayList<>();
String partial = args[1].toLowerCase();
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.getName().toLowerCase().startsWith(partial)) {
players.add(p.getName());
}
}
return players;
}
}
return new ArrayList<>();
}
private List<String> completeToggleArgs(String partialInput) {
List<String> completions = new ArrayList<>();
String partial = partialInput.toLowerCase();
for (String option : List.of("on", "off", "toggle")) {
if (option.startsWith(partial)) {
completions.add(option);
}
}
return completions;
}
}

View File

@@ -1,17 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class LoomCommand extends BaseCommand {
public LoomCommand() {
super("essentialsc.command.loom");
}
@Override
protected boolean execute(Player player, String[] args) {
// 使用 Paper API 打开织布机(标题跟随客户端语言)
player.openLoom(null, true);
playBlockShortcutSound(player, Material.LOOM, Sound.UI_LOOM_SELECT_PATTERN);
return true;
}
}

View File

@@ -9,19 +9,19 @@ import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 生物掉落物控制命令
* /mobdrops - 打开控制菜单
*/
public class MobDropCommand extends BaseCommand {
private static final int MENU_SIZE = 27;
private static final int ENDERMAN_SLOT = 13;
public static final class MobDropMenuHolder implements InventoryHolder {
private final Inventory inventory;
public MobDropMenuHolder(String title) {
this.inventory = Bukkit.createInventory(this, 27, title);
this.inventory = Bukkit.createInventory(this, MENU_SIZE, title);
}
@Override
@@ -29,53 +29,60 @@ public class MobDropCommand extends BaseCommand {
return inventory;
}
}
public MobDropCommand() {
super("essentialsc.mobdrops.enderman");
}
@Override
protected boolean execute(Player player, String[] args) {
openMobDropMenu(player);
return true;
}
/**
* 打开生物掉落控制菜单
*/
private void openMobDropMenu(Player player) {
// 读取当前配置
public static void openMobDropMenu(EssentialsC plugin, Player player) {
var lang = EssentialsC.getLangManager();
boolean endermanEnabled = plugin.getConfig().getBoolean("mob-drops.enderman.enabled", true);
// 创建菜单
Inventory menu = new MobDropMenuHolder("§6§l生物掉落控制").getInventory();
// 末影人控制项
String status = lang.getString(endermanEnabled
? "mobdrops-menu.status.enabled"
: "mobdrops-menu.status.disabled");
Inventory menu = new MobDropMenuHolder(lang.getString("mobdrops-menu.title")).getInventory();
ItemStack endermanItem = new ItemStack(Material.ENDER_PEARL);
ItemMeta endermanMeta = endermanItem.getItemMeta();
endermanMeta.setDisplayName("§d末影人掉落");
endermanMeta.setLore(Arrays.asList(
"§7当前状态: " + (endermanEnabled ? "§a✅ 开启" : "§c❌ 关闭"),
"",
"§e点击切换状态"
));
endermanItem.setItemMeta(endermanMeta);
// 放置在中间
menu.setItem(13, endermanItem);
// 装饰物品
if (endermanMeta != null) {
endermanMeta.setDisplayName(lang.getString("mobdrops-menu.enderman.name"));
endermanMeta.setLore(List.of(
lang.getString("mobdrops-menu.enderman.status", Map.of("status", status)),
"",
lang.getString("mobdrops-menu.enderman.toggle")
));
endermanItem.setItemMeta(endermanMeta);
}
menu.setItem(ENDERMAN_SLOT, endermanItem);
ItemStack glass = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
ItemMeta glassMeta = glass.getItemMeta();
glassMeta.setDisplayName(" ");
glass.setItemMeta(glassMeta);
for (int i = 0; i < 27; i++) {
if (menu.getItem(i) == null) {
menu.setItem(i, glass);
if (glassMeta != null) {
glassMeta.setDisplayName(" ");
glass.setItemMeta(glassMeta);
}
for (int slot = 0; slot < MENU_SIZE; slot++) {
if (menu.getItem(slot) == null) {
menu.setItem(slot, glass);
}
}
player.openInventory(menu);
}
public static int getEndermanSlot() {
return ENDERMAN_SLOT;
}
private void openMobDropMenu(Player player) {
openMobDropMenu(plugin, player);
}
}

View File

@@ -0,0 +1,61 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.persistence.PersistentDataType;
public class NightVisionCommand extends BaseCommand {
private final NamespacedKey enabledKey;
public NightVisionCommand() {
super("essentialsc.command.nightvision");
this.enabledKey = new NamespacedKey(plugin, "nightvision_enabled");
}
@Override
protected boolean execute(Player player, String[] args) {
boolean currentState = isPluginNightVisionEnabled(player);
Boolean targetState = resolveTargetState(currentState, args);
if (targetState == null) {
player.sendMessage(getLang().getPrefixedString("messages.nightvision-usage"));
return true;
}
if (targetState) {
player.addPotionEffect(new PotionEffect(PotionEffectType.NIGHT_VISION, Integer.MAX_VALUE, 0, false, false, false));
player.getPersistentDataContainer().set(enabledKey, PersistentDataType.BYTE, (byte) 1);
playShortcutSound(player, Sound.BLOCK_BEACON_POWER_SELECT);
player.sendMessage(getLang().getPrefixedString("messages.nightvision-enabled"));
} else {
if (currentState) {
player.removePotionEffect(PotionEffectType.NIGHT_VISION);
player.getPersistentDataContainer().remove(enabledKey);
}
playShortcutSound(player, Sound.BLOCK_BEACON_DEACTIVATE);
player.sendMessage(getLang().getPrefixedString("messages.nightvision-disabled"));
}
return true;
}
private Boolean resolveTargetState(boolean currentState, String[] args) {
if (args.length == 0) {
return !currentState;
}
return switch (args[0].toLowerCase()) {
case "on", "true", "enable", "enabled" -> true;
case "off", "false", "disable", "disabled" -> false;
case "toggle" -> !currentState;
default -> null;
};
}
private boolean isPluginNightVisionEnabled(Player player) {
Byte value = player.getPersistentDataContainer().get(enabledKey, PersistentDataType.BYTE);
return value != null && value == (byte) 1;
}
}

View File

@@ -3,80 +3,71 @@ package cn.infstar.essentialsC.commands;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class RepairCommand extends BaseCommand {
public RepairCommand() {
super("essentialsc.command.repair");
}
@Override
protected boolean execute(@NotNull Player player, String[] args) {
protected boolean execute(Player player, String[] args) {
if (args.length > 0 && args[0].equalsIgnoreCase("all")) {
// 检查是否有修复全部的权限
if (!player.hasPermission("essentialsc.command.repair.all")) {
player.sendMessage(getLang().getString("messages.no-permission-repair-all"));
player.sendMessage(getLang().getPrefixedString("messages.no-permission-repair-all"));
return true;
}
int repairedCount = repairAll(player);
if (repairedCount > 0) {
player.sendMessage(getLang().getString("messages.repair-all-success", java.util.Map.of("count", String.valueOf(repairedCount))));
player.sendMessage(getLang().getPrefixedString("messages.repair-all-success",
Map.of("count", String.valueOf(repairedCount))));
} else {
player.sendMessage(getLang().getString("messages.repair-no-items"));
player.sendMessage(getLang().getPrefixedString("messages.repair-no-items"));
}
return true;
}
ItemStack item = player.getInventory().getItemInMainHand();
if (item == null || item.getType().isAir()) {
player.sendMessage(getLang().getPrefixedString("messages.repair-no-item-in-hand"));
return true;
}
if (repairItem(item)) {
player.sendMessage(getLang().getPrefixedString("messages.repair-hand-success"));
} else {
// 修复手中物品
ItemStack item = player.getInventory().getItemInMainHand();
if (item == null || item.getType().isAir()) {
player.sendMessage(getLang().getString("messages.repair-no-item-in-hand"));
return true;
}
if (repairItem(item)) {
player.sendMessage(getLang().getString("messages.repair-hand-success"));
} else {
player.sendMessage(getLang().getString("messages.repair-not-damaged"));
}
player.sendMessage(getLang().getPrefixedString("messages.repair-not-damaged"));
}
return true;
}
private boolean repairItem(ItemStack item) {
if (item.getItemMeta() instanceof Damageable damageable) {
if (damageable.hasDamage()) {
Damageable newMeta = (Damageable) damageable.clone();
newMeta.setDamage(0);
item.setItemMeta((org.bukkit.inventory.meta.ItemMeta) newMeta);
return true;
}
if (item.getItemMeta() instanceof Damageable damageable && damageable.hasDamage()) {
Damageable newMeta = (Damageable) damageable.clone();
newMeta.setDamage(0);
item.setItemMeta((org.bukkit.inventory.meta.ItemMeta) newMeta);
return true;
}
return false;
}
private int repairAll(Player player) {
int count = 0;
ItemStack[] contents = player.getInventory().getContents();
for (ItemStack item : contents) {
if (item != null && !item.getType().isAir()) {
if (repairItem(item)) {
count++;
}
for (ItemStack item : player.getInventory().getContents()) {
if (item != null && !item.getType().isAir() && repairItem(item)) {
count++;
}
}
// 也修复盔甲栏
ItemStack[] armor = player.getInventory().getArmorContents();
for (ItemStack item : armor) {
if (item != null && !item.getType().isAir()) {
if (repairItem(item)) {
count++;
}
for (ItemStack item : player.getInventory().getArmorContents()) {
if (item != null && !item.getType().isAir() && repairItem(item)) {
count++;
}
}
player.updateInventory();
return count;
}

View File

@@ -1,55 +1,57 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
public class SeenCommand extends BaseCommand {
public SeenCommand() {
super("essentialsc.command.seen");
}
@Override
protected boolean execute(@NotNull Player player, String[] args) {
protected boolean execute(Player player, String[] args) {
if (args.length == 0) {
player.sendMessage(getLang().getString("messages.seen-usage"));
player.sendMessage(getLang().getPrefixedString("messages.seen-usage"));
return true;
}
OfflinePlayer target = Bukkit.getOfflinePlayer(args[0]);
if (!target.hasPlayedBefore() && !target.isOnline()) {
player.sendMessage(getLang().getString("messages.player-not-found", Map.of("player", args[0])));
player.sendMessage(getLang().getPrefixedString("messages.player-not-found", Map.of("player", args[0])));
return true;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
StringBuilder info = new StringBuilder();
info.append("§6========== §e玩家信息 §6==========\n");
info.append("§7玩家名称: §f").append(target.getName()).append("\n");
info.append(getLang().getPrefix()).append(ChatColor.GOLD).append("Player info: ")
.append(ChatColor.WHITE).append(target.getName()).append("\n");
if (target.isOnline()) {
info.append("§7状态: §a在线\n");
info.append(ChatColor.GRAY).append("Status: ").append(ChatColor.GREEN).append("Online").append("\n");
Player onlinePlayer = target.getPlayer();
if (onlinePlayer != null) {
info.append("§7所在世界: §f").append(onlinePlayer.getWorld().getName()).append("\n");
info.append(ChatColor.GRAY).append("World: ").append(ChatColor.WHITE)
.append(onlinePlayer.getWorld().getName()).append("\n");
}
} else {
info.append("§7状态: §c离线\n");
info.append(ChatColor.GRAY).append("Status: ").append(ChatColor.RED).append("Offline").append("\n");
long lastSeen = target.getLastSeen();
if (lastSeen > 0) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
info.append("§7最后上线: §f").append(sdf.format(new Date(lastSeen))).append("\n");
info.append(ChatColor.GRAY).append("Last seen: ").append(ChatColor.WHITE)
.append(format.format(new Date(lastSeen))).append("\n");
}
}
info.append("§7首次加入: §f").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(target.getFirstPlayed()))).append("\n");
info.append("§6=============================");
info.append(ChatColor.GRAY).append("First joined: ").append(ChatColor.WHITE)
.append(format.format(new Date(target.getFirstPlayed())));
player.sendMessage(info.toString());
return true;
}

View File

@@ -1,17 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class SmithingTableCommand extends BaseCommand {
public SmithingTableCommand() {
super("essentialsc.command.smithingtable");
}
@Override
protected boolean execute(Player player, String[] args) {
// 使用 Paper API 打开锻造台(标题跟随客户端语言)
player.openSmithingTable(null, true);
playBlockShortcutSound(player, Material.SMITHING_TABLE, Sound.BLOCK_SMITHING_TABLE_USE);
return true;
}
}

View File

@@ -1,17 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class StonecutterCommand extends BaseCommand {
public StonecutterCommand() {
super("essentialsc.command.stonecutter");
}
@Override
protected boolean execute(Player player, String[] args) {
// 使用 Paper API 打开切石机(标题跟随客户端语言)
player.openStonecutter(null, true);
playBlockShortcutSound(player, Material.STONECUTTER, Sound.UI_STONECUTTER_SELECT_RECIPE);
return true;
}
}

View File

@@ -2,20 +2,15 @@ package cn.infstar.essentialsC.commands;
import org.bukkit.entity.Player;
import java.util.Map;
public class SuicideCommand extends BaseCommand {
public SuicideCommand() {
super("essentialsc.command.suicide");
}
@Override
protected boolean execute(Player player, String[] args) {
String message = getLang().getString("messages.suicide-message",
Map.of("player", player.getName()));
player.setHealth(0);
// 消息会在玩家死亡后显示,所以这里不发送
return true;
}
}

View File

@@ -0,0 +1,89 @@
package cn.infstar.essentialsC.commands;
import cn.infstar.essentialsC.tpsbar.TpsBarService;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class TpsBarCommand extends BaseCommand implements TabCompleter {
public TpsBarCommand() {
super("essentialsc.command.tpsbar");
}
@Override
protected boolean execute(Player player, String[] args) {
TpsBarService tpsBarService = plugin.getTpsBarManager();
if (tpsBarService == null) {
player.sendMessage(getLang().getPrefixedString("messages.player-only"));
return true;
}
if (args.length == 0) {
boolean enabled = tpsBarService.toggle(player);
tpsBarService.sendToggleMessage(player, player, enabled);
return true;
}
if (args.length != 1) {
player.sendMessage(tpsBarService.getUsageMessage());
return true;
}
if (!player.hasPermission("essentialsc.command.tpsbar.others")) {
player.sendMessage(getLang().getPrefixedString("messages.no-permission",
Map.of("permission", "essentialsc.command.tpsbar.others")));
return true;
}
Collection<Player> targets = tpsBarService.resolveTargets(player, args[0]);
if (targets.isEmpty()) {
Player exactPlayer = Bukkit.getPlayerExact(args[0]);
if (exactPlayer == null) {
player.sendMessage(tpsBarService.getPlayerNotFoundMessage(args[0]));
} else {
player.sendMessage(tpsBarService.getNoTargetsMessage());
}
return true;
}
for (Player target : targets) {
boolean enabled = tpsBarService.toggle(target);
tpsBarService.sendToggleMessage(player, target, enabled);
}
return true;
}
@Override
protected boolean executeConsole(CommandSender sender, String[] args) {
sender.sendMessage(getLang().getPrefixedString("messages.player-only"));
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if (args.length != 1 || !(sender instanceof Player player)) {
return List.of();
}
if (!player.hasPermission("essentialsc.command.tpsbar.others")) {
return List.of();
}
String partial = args[0].toLowerCase();
List<String> completions = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (onlinePlayer.getName().toLowerCase().startsWith(partial)) {
completions.add(onlinePlayer.getName());
}
}
return completions;
}
}

View File

@@ -1,38 +1,35 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class VanishCommand extends BaseCommand {
private static final Set<UUID> vanishedPlayers = new HashSet<>();
public VanishCommand() {
super("essentialsc.command.vanish");
}
@Override
protected boolean execute(@NotNull Player player, String[] args) {
protected boolean execute(Player player, String[] args) {
UUID uuid = player.getUniqueId();
if (vanishedPlayers.contains(uuid)) {
// 取消隐身
vanishedPlayers.remove(uuid);
showPlayerToAll(player);
player.sendMessage(getLang().getString("messages.vanish-disabled"));
player.sendMessage(getLang().getPrefixedString("messages.vanish-disabled"));
} else {
// 开启隐身
vanishedPlayers.add(uuid);
hidePlayerFromAll(player);
player.sendMessage(getLang().getString("messages.vanish-enabled"));
player.sendMessage(getLang().getPrefixedString("messages.vanish-enabled"));
}
return true;
}
private void hidePlayerFromAll(Player player) {
for (Player online : player.getServer().getOnlinePlayers()) {
if (online != player) {
@@ -40,7 +37,7 @@ public class VanishCommand extends BaseCommand {
}
}
}
private void showPlayerToAll(Player player) {
for (Player online : player.getServer().getOnlinePlayers()) {
if (online != player) {
@@ -48,7 +45,7 @@ public class VanishCommand extends BaseCommand {
}
}
}
public static boolean isVanished(Player player) {
return vanishedPlayers.contains(player.getUniqueId());
}

View File

@@ -1,17 +1,19 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class WorkbenchCommand extends BaseCommand {
public WorkbenchCommand() {
super("essentialsc.command.workbench");
}
@Override
protected boolean execute(Player player, String[] args) {
// 打开工作台(标题由客户端语言决定)
player.openWorkbench(null, true);
playBlockShortcutSound(player, Material.CRAFTING_TABLE, Sound.BLOCK_CRAFTER_CRAFT);
return true;
}
}