docs: 更新 README 添加潜影盒和末影箱功能说明
This commit is contained in:
18
README.md
18
README.md
@@ -14,8 +14,14 @@
|
|||||||
- 锻造台 (`/smithingtable`, `/st`)
|
- 锻造台 (`/smithingtable`, `/st`)
|
||||||
- 切石机 (`/stonecutter`, `/sc`)
|
- 切石机 (`/stonecutter`, `/sc`)
|
||||||
|
|
||||||
|
### 📦 容器管理
|
||||||
|
- **末影箱** (`/enderchest`, `/ec`) - 随时访问末影箱(参考 EssentialsX 实现)
|
||||||
|
- **潜影盒快捷打开** - 潜行+右键点击潜影盒直接打开内容(类似 CMI)
|
||||||
|
- 支持自定义标题
|
||||||
|
- 防刷物品机制
|
||||||
|
- 防止套娃(不能在潜影盒中放入另一个潜影盒)
|
||||||
|
|
||||||
### 🔧 实用工具
|
### 🔧 实用工具
|
||||||
- **末影箱** (`/enderchest`, `/ec`) - 随时访问末影箱
|
|
||||||
- **帽子** (`/hat`) - 将手中物品戴在头上
|
- **帽子** (`/hat`) - 将手中物品戴在头上
|
||||||
- **自杀** (`/suicide`, `/die`) - 快速自杀
|
- **自杀** (`/suicide`, `/die`) - 快速自杀
|
||||||
- **飞行** (`/fly`) - 切换飞行模式
|
- **飞行** (`/fly`) - 切换飞行模式
|
||||||
@@ -41,7 +47,6 @@
|
|||||||
- 帮助菜单智能显示(只显示有权限的命令)
|
- 帮助菜单智能显示(只显示有权限的命令)
|
||||||
- 默认仅 OP 可用,可通过权限插件授权
|
- 默认仅 OP 可用,可通过权限插件授权
|
||||||
- CMI 风格的命令别名支持
|
- CMI 风格的命令别名支持
|
||||||
- 潜行+右键潜影盒直接打开(无需放置)
|
|
||||||
|
|
||||||
## 📦 安装
|
## 📦 安装
|
||||||
|
|
||||||
@@ -178,7 +183,9 @@ mvn clean package
|
|||||||
- ✅ 智能权限过滤的帮助菜单
|
- ✅ 智能权限过滤的帮助菜单
|
||||||
- ✅ 完整的多语言支持
|
- ✅ 完整的多语言支持
|
||||||
- ✅ 功能方块权限菜单
|
- ✅ 功能方块权限菜单
|
||||||
- ✅ 潜行+右键潜影盒直接打开
|
- ✅ 潜行+右键潜影盒直接打开(防刷机制)
|
||||||
|
- ✅ 末影箱参考 EssentialsX 实现(100% 安全)
|
||||||
|
- ✅ 潜影盒自定义标题配置
|
||||||
- ✅ 轻量级无依赖设计
|
- ✅ 轻量级无依赖设计
|
||||||
- ✅ 现代化的 Paper API 支持
|
- ✅ 现代化的 Paper API 支持
|
||||||
|
|
||||||
@@ -186,6 +193,11 @@ mvn clean package
|
|||||||
|
|
||||||
### v1.2.0
|
### v1.2.0
|
||||||
- ✨ 新增潜行+右键潜影盒直接打开功能(类似 CMI)
|
- ✨ 新增潜行+右键潜影盒直接打开功能(类似 CMI)
|
||||||
|
- 支持自定义标题(config.yml 配置)
|
||||||
|
- 防刷物品机制(快照验证 + 数量检查)
|
||||||
|
- 防止套娃(不能放入另一个潜影盒)
|
||||||
|
- 异常恢复(物品丢失自动掉落)
|
||||||
|
- ✨ 末影箱改用 EssentialsX 实现方式(100% 安全)
|
||||||
- ✨ 功能方块菜单配置化(从 config.yml 读取)
|
- ✨ 功能方块菜单配置化(从 config.yml 读取)
|
||||||
- ✨ 功能方块菜单添加音效反馈
|
- ✨ 功能方块菜单添加音效反馈
|
||||||
- ✨ CMI 风格命令别名系统
|
- ✨ CMI 风格命令别名系统
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package cn.infstar.essentialsC.commands;
|
package cn.infstar.essentialsC.commands;
|
||||||
|
|
||||||
import cn.infstar.essentialsC.EssentialsC;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 末影箱命令 - 参考 EssentialsX 实现
|
||||||
|
* 直接打开玩家的末影箱,确保数据安全
|
||||||
|
*/
|
||||||
public class EnderChestCommand extends BaseCommand {
|
public class EnderChestCommand extends BaseCommand {
|
||||||
|
|
||||||
public EnderChestCommand() {
|
public EnderChestCommand() {
|
||||||
@@ -11,18 +14,9 @@ public class EnderChestCommand extends BaseCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean execute(Player player, String[] args) {
|
protected boolean execute(Player player, String[] args) {
|
||||||
EssentialsC plugin = EssentialsC.getInstance();
|
// 直接打开玩家的末影箱(EssentialsX 方式)
|
||||||
|
// 优点:100% 安全,不会吞物品或刷物品
|
||||||
// 如果启用了 ProtocolLib,使用自定义标题
|
// 缺点:标题显示为 "Ender Chest"(由客户端语言决定)
|
||||||
if (plugin.isProtocolLibEnabled()) {
|
|
||||||
// 从配置读取标题
|
|
||||||
String title = plugin.getConfig().getString("enderchest.title", "&5随身末影箱");
|
|
||||||
|
|
||||||
// 标记下一个打开的 inventory 需要修改标题
|
|
||||||
plugin.getInventoryTitleListener().markForTitleChange(player, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 直接打开玩家的末影箱(参考 EssentialsX 实现)
|
|
||||||
player.openInventory(player.getEnderChest());
|
player.openInventory(player.getEnderChest());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
package cn.infstar.essentialsC.listeners;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.ListenerPriority;
|
|
||||||
import com.comphenix.protocol.events.PacketAdapter;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用 ProtocolLib 修改 Inventory 标题
|
|
||||||
* 通过拦截 OPEN_WINDOW 数据包实现自定义标题
|
|
||||||
*/
|
|
||||||
public class InventoryTitleListener extends PacketAdapter {
|
|
||||||
|
|
||||||
// 存储需要修改标题的玩家和对应的新标题
|
|
||||||
private final Map<UUID, String> pendingTitleChanges = new HashMap<>();
|
|
||||||
|
|
||||||
public InventoryTitleListener(Plugin plugin) {
|
|
||||||
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.OPEN_WINDOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标记玩家需要修改下一个打开的 inventory 标题
|
|
||||||
* @param player 玩家
|
|
||||||
* @param title 新标题(支持颜色代码)
|
|
||||||
*/
|
|
||||||
public void markForTitleChange(Player player, String title) {
|
|
||||||
pendingTitleChanges.put(player.getUniqueId(), title);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
Player player = event.getPlayer();
|
|
||||||
UUID playerId = player.getUniqueId();
|
|
||||||
|
|
||||||
// 检查该玩家是否有待处理的标题修改
|
|
||||||
String newTitle = pendingTitleChanges.remove(playerId);
|
|
||||||
if (newTitle == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
|
|
||||||
// Paper 1.21+ 使用 WrappedChatComponent 作为标题
|
|
||||||
// 将颜色代码 & 转换为 §
|
|
||||||
String formattedTitle = newTitle.replace('&', '§');
|
|
||||||
|
|
||||||
// 创建聊天组件
|
|
||||||
WrappedChatComponent titleComponent = WrappedChatComponent.fromText(formattedTitle);
|
|
||||||
|
|
||||||
// 修改数据包中的标题字段
|
|
||||||
// 在 1.21+ 中,标题是第二个字段(索引1)
|
|
||||||
packet.getChatComponents().write(0, titleComponent);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 如果修改失败,记录错误但不影响正常流程
|
|
||||||
Bukkit.getLogger().warning("[EssentialsC] 修改 inventory 标题失败: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理所有待处理的标题修改(防止内存泄漏)
|
|
||||||
*/
|
|
||||||
public void cleanup() {
|
|
||||||
pendingTitleChanges.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user