feat: 添加潜影盒快捷打开和末影箱自定义标题功能

This commit is contained in:
Coldsmile_7
2026-04-15 00:55:31 +08:00
parent f6364ac36b
commit cc07647551
62 changed files with 15171 additions and 304 deletions

View File

@@ -1,143 +0,0 @@
package cn.infstar.essentialsC.commands;
import cn.infstar.essentialsC.EssentialsC;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public class AdminMenuCommand extends BaseCommand implements Listener {
private static final int MENU_SIZE = 27;
public AdminMenuCommand() {
super("essentialsc.command.admin");
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@Override
protected boolean execute(@NotNull Player player, String[] args) {
openMenu(player);
return true;
}
private void openMenu(Player player) {
String title = plugin.getConfig().getString("admin-menu.title", "&6EssentialsC 管理菜单");
Inventory menu = Bukkit.createInventory(null, MENU_SIZE, translateColor(title));
// 从配置中读取所有物品
var itemsConfig = plugin.getConfig().getConfigurationSection("admin-menu.items");
if (itemsConfig == null) return;
for (String key : itemsConfig.getKeys(false)) {
var section = itemsConfig.getConfigurationSection(key);
if (section == null) continue;
int slot = section.getInt("slot");
Material material = Material.matchMaterial(section.getString("material", "STONE"));
if (material == null) material = Material.STONE;
String name = translateColor(section.getString("name", "&fItem"));
java.util.List<String> lore = section.getStringList("lore").stream()
.map(this::translateColor)
.collect(java.util.stream.Collectors.toList());
addItem(menu, slot, material, name, lore);
}
player.openInventory(menu);
}
private String translateColor(String text) {
return text.replace("&", "§");
}
private void addItem(Inventory inv, int slot, Material material, String name, java.util.List<String> lore) {
ItemStack item = new ItemStack(material);
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(name);
meta.setLore(lore);
item.setItemMeta(meta);
}
inv.setItem(slot, item);
}
@EventHandler
public void onMenuClick(InventoryClickEvent event) {
// 检查是否是管理员菜单
String configTitle = translateColor(plugin.getConfig().getString("admin-menu.title", "&6EssentialsC 管理菜单"));
if (!event.getView().getTitle().equals(configTitle)) return;
if (!(event.getWhoClicked() instanceof Player player)) return;
// 取消事件,防止拿出物品
event.setCancelled(true);
ItemStack clicked = event.getCurrentItem();
if (clicked == null || !clicked.hasItemMeta()) return;
String displayName = clicked.getItemMeta().getDisplayName();
// 从配置中读取所有物品配置,通过名称匹配
var itemsConfig = plugin.getConfig().getConfigurationSection("admin-menu.items");
if (itemsConfig == null) return;
for (String key : itemsConfig.getKeys(false)) {
var section = itemsConfig.getConfigurationSection(key);
if (section == null) continue;
String itemName = translateColor(section.getString("name", ""));
if (!displayName.equals(itemName)) continue;
// 找到匹配的物品,执行对应操作
switch (key) {
case "time-control" -> {
if (event.isLeftClick()) player.getWorld().setTime(1000);
else player.getWorld().setTime(13000);
player.sendMessage(getLang().getString("admin-time-set"));
}
case "weather-control" -> {
if (event.isLeftClick()) player.getWorld().setStorm(false);
else player.getWorld().setStorm(true);
player.sendMessage(getLang().getString("admin-weather-set"));
}
case "heal-self" -> {
player.setHealth(player.getMaxHealth());
player.setFoodLevel(20);
player.sendMessage(getLang().getString("admin-heal-success"));
}
case "feed-self" -> {
player.setFoodLevel(20);
player.setSaturation(20f);
player.sendMessage(getLang().getString("admin-feed-success"));
}
case "repair-hand" -> {
var item = player.getInventory().getItemInMainHand();
if (item.getItemMeta() instanceof org.bukkit.inventory.meta.Damageable d) {
d.setDamage(0);
item.setItemMeta((org.bukkit.inventory.meta.ItemMeta) d);
player.sendMessage(getLang().getString("admin-repair-success"));
}
}
case "vanish" -> {
HelpCommand.COMMAND_CACHE.get("vanish").execute(player, new String[]{});
openMenu(player); // 刷新菜单
}
case "reload" -> {
plugin.reloadConfig();
EssentialsC.getLangManager().reload();
player.sendMessage(getLang().getString("admin-reload-success"));
}
}
break; // 找到后退出循环
}
}
}

View File

@@ -10,8 +10,8 @@ public class AnvilCommand extends BaseCommand {
@Override
protected boolean execute(Player player, String[] args) {
// 使用 Paper API 打开铁砧(标题跟随客户端语言)
player.openAnvil(null, true);
player.sendMessage(getLang().getString("anvil-opened"));
return true;
}
}

View File

@@ -0,0 +1,128 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
public class BlocksMenuCommand extends BaseCommand implements Listener {
private static final int MENU_SIZE = 36;
private final NamespacedKey blockKey;
public BlocksMenuCommand() {
super("essentialsc.command.blocks");
plugin.getServer().getPluginManager().registerEvents(this, plugin);
blockKey = new NamespacedKey(plugin, "block_key");
}
@Override
protected boolean execute(@NotNull Player player, String[] args) {
openMenu(player);
return true;
}
private void openMenu(Player player) {
String title = plugin.getConfig().getString("blocks-menu.title", "&6&lEssentialsC &8- &e&l功能方块菜单");
Inventory menu = Bukkit.createInventory(null, MENU_SIZE, translateColor(title));
// 从配置中读取所有物品
var itemsConfig = plugin.getConfig().getConfigurationSection("blocks-menu.items");
if (itemsConfig == null) return;
for (String key : itemsConfig.getKeys(false)) {
var section = itemsConfig.getConfigurationSection(key);
if (section == null) continue;
// 检查权限
String permission = section.getString("permission");
if (permission != null && !player.hasPermission(permission)) {
continue;
}
int slot = section.getInt("slot");
Material material = Material.matchMaterial(section.getString("material", "STONE"));
if (material == null) material = Material.STONE;
String name = translateColor(section.getString("name", "&fItem"));
java.util.List<String> lore = section.getStringList("lore").stream()
.map(this::translateColor)
.collect(java.util.stream.Collectors.toList());
addItem(menu, slot, material, name, lore, key);
}
player.openInventory(menu);
}
private void addItem(Inventory inv, int slot, Material material, String name, java.util.List<String> lore, String key) {
ItemStack item = new ItemStack(material);
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(name);
meta.setLore(lore);
meta.getPersistentDataContainer().set(this.blockKey, PersistentDataType.STRING, key);
item.setItemMeta(meta);
}
inv.setItem(slot, item);
}
@EventHandler
public void onMenuClick(InventoryClickEvent event) {
// 动态获取配置的标题
String configTitle = plugin.getConfig().getString("blocks-menu.title", "&6&lEssentialsC &8- &e&l功能方块菜单");
String actualTitle = translateColor(configTitle);
if (!event.getView().getTitle().equals(actualTitle)) return;
if (!(event.getWhoClicked() instanceof Player player)) 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);
// 点击后执行对应命令并播放音效(如果有)
if (key != null && HelpCommand.COMMAND_CACHE.containsKey(key)) {
playBlockOpenSound(player, key);
HelpCommand.COMMAND_CACHE.get(key).execute(player, new String[]{});
}
}
/**
* 播放对应方块的打开音效(优先使用交互音效)
*/
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;
};
if (sound != null) {
player.playSound(player.getLocation(), sound, 1.0f, 1.0f);
}
}
/**
* 转换颜色代码 & -> §
*/
private String translateColor(String text) {
return text.replace("&", "§");
}
}

View File

@@ -1,17 +0,0 @@
package cn.infstar.essentialsC.commands;
import org.bukkit.entity.Player;
public class EnchantingTableCommand extends BaseCommand {
public EnchantingTableCommand() {
super("essentialsc.command.enchantingtable");
}
@Override
protected boolean execute(Player player, String[] args) {
player.openEnchanting(null, true);
player.sendMessage(getLang().getString("enchantingtable-opened"));
return true;
}
}

View File

@@ -1,5 +1,6 @@
package cn.infstar.essentialsC.commands;
import cn.infstar.essentialsC.EssentialsC;
import org.bukkit.entity.Player;
public class EnderChestCommand extends BaseCommand {
@@ -10,7 +11,18 @@ public class EnderChestCommand extends BaseCommand {
@Override
protected boolean execute(Player player, String[] args) {
// 打开玩家的末影箱(标题由客户端决定)
EssentialsC plugin = EssentialsC.getInstance();
// 如果启用了 ProtocolLib使用自定义标题
if (plugin.isProtocolLibEnabled()) {
// 从配置读取标题
String title = plugin.getConfig().getString("enderchest.title", "&5随身末影箱");
// 标记下一个打开的 inventory 需要修改标题
plugin.getInventoryTitleListener().markForTitleChange(player, title);
}
// 直接打开玩家的末影箱(参考 EssentialsX 实现)
player.openInventory(player.getEnderChest());
return true;
}

View File

@@ -21,7 +21,6 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
static {
COMMAND_CACHE.put("workbench", new WorkbenchCommand());
COMMAND_CACHE.put("anvil", new AnvilCommand());
COMMAND_CACHE.put("enchantingtable", new EnchantingTableCommand());
COMMAND_CACHE.put("cartographytable", new CartographyTableCommand());
COMMAND_CACHE.put("grindstone", new GrindstoneCommand());
COMMAND_CACHE.put("loom", new LoomCommand());
@@ -36,7 +35,7 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
COMMAND_CACHE.put("seen", new SeenCommand());
COMMAND_CACHE.put("feed", new FeedCommand());
COMMAND_CACHE.put("repair", new RepairCommand());
COMMAND_CACHE.put("admin", new AdminMenuCommand());
COMMAND_CACHE.put("blocks", new BlocksMenuCommand());
}
public HelpCommand() {
@@ -49,14 +48,7 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
String subCommand = args[0].toLowerCase();
// 管理相关
if (subCommand.equals("admin")) {
if (!player.hasPermission("essentialsc.command.admin")) {
player.sendMessage(getLang().getString("messages.no-permission"));
return true;
}
COMMAND_CACHE.get("admin").execute(player, new String[]{});
return true;
} else if (subCommand.equals("reload")) {
if (subCommand.equals("reload")) {
if (!player.hasPermission("essentialsc.command.reload")) {
player.sendMessage(getLang().getString("messages.no-permission"));
return true;
@@ -119,10 +111,6 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
blockCommands.append(lang.getString("help.commands.anvil")).append("\n");
hasBlockCommands = true;
}
if (player.hasPermission("essentialsc.command.enchantingtable")) {
blockCommands.append(lang.getString("help.commands.enchantingtable")).append("\n");
hasBlockCommands = true;
}
if (player.hasPermission("essentialsc.command.cartographytable")) {
blockCommands.append(lang.getString("help.commands.cartographytable")).append("\n");
hasBlockCommands = true;
@@ -182,10 +170,6 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
otherCommands.append(lang.getString("help.commands.seen")).append("\n");
hasOtherCommands = true;
}
if (player.hasPermission("essentialsc.command.admin")) {
otherCommands.append(lang.getString("help.commands.admin")).append("\n");
hasOtherCommands = true;
}
if (hasOtherCommands) {
player.sendMessage(lang.getString("help.section-other"));
@@ -203,7 +187,6 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
private String getActualCommand(String alias) {
return switch (alias) {
case "wb" -> "workbench";
case "enchant", "et" -> "enchantingtable";
case "cartography", "ct" -> "cartographytable";
case "gs" -> "grindstone";
case "smithing", "st" -> "smithingtable";
@@ -231,14 +214,11 @@ public class HelpCommand extends BaseCommand implements TabCompleter {
// 所有可能的子命令及其权限(包括别名)
String[][] subCommands = {
{"admin", "essentialsc.command.admin"},
{"reload", "essentialsc.command.reload"},
{"blocks", "essentialsc.command.blocks"},
{"workbench", "essentialsc.command.workbench"},
{"wb", "essentialsc.command.workbench"},
{"anvil", "essentialsc.command.anvil"},
{"enchantingtable", "essentialsc.command.enchantingtable"},
{"enchant", "essentialsc.command.enchantingtable"},
{"et", "essentialsc.command.enchantingtable"},
{"cartographytable", "essentialsc.command.cartographytable"},
{"cartography", "essentialsc.command.cartographytable"},
{"ct", "essentialsc.command.cartographytable"},