【深度解析】EssentialsX控制台/recipe命令格式化异常的根源与修复方案

【深度解析】EssentialsX控制台/recipe命令格式化异常的根源与修复方案

【免费下载链接】Essentials The modern Essentials suite for Spigot and Paper. 【免费下载链接】Essentials 项目地址: https://gitcode.com/GitHub_Trending/es/Essentials

问题现象与影响范围

当服务器管理员通过控制台执行/recipe命令时,输出内容常出现<green><white>等原始MiniMessage标签(如<green>铁锭</green>),而非预期的格式化文本。此问题仅存在于控制台环境,玩家通过游戏内执行相同命令可正常显示格式化内容。经测试,该问题影响EssentialsX 2.19.0至2.20.1版本,涉及Spigot/Paper 1.18-1.20.1服务端。

技术原理分析

命令执行流程图

mermaid

核心矛盾点

// Console.java中的问题代码
public void sendTl(String tlKey, Object... args) {
    final String translation = tlLiteral(tlKey, args);
    // 控制台环境直接使用MiniMessage解析,导致原始标签输出
    final Component component = AdventureUtil.miniMessage().deserialize(translation);
    consoleAudience.sendMessage(component);
}

对比玩家端正确实现:

// User.java中的正确实现
public void sendTl(String tlKey, Object... args) {
    String message = tl(tlKey, args);
    // 玩家端会先移除格式标签再应用游戏内格式
    message = StringUtil.color(message, this);
    sendMessage(message);
}

问题根源追溯

1. 翻译文本处理流程差异

模块文本来源格式化处理终端支持度
控制台tlLiteral()直接返回带标签文本MiniMessage.deserialize()不支持ANSI转义
玩家端tl()返回原始文本StringUtil.color()转义§代码支持Minecraft格式

2. AdventureUtil工具类的设计缺陷

// AdventureUtil.java中的关键实现
public static ParsedPlaceholder parsed(final String literal) {
    // 无条件启用MiniMessage解析,未考虑控制台场景
    return new ParsedPlaceholder(literal);
}

在Commandrecipe.java中,开发者明确使用了格式化占位符:

// 问题调用点
sender.sendTl("recipeWhere", AdventureUtil.parsed(s.toString()));

解决方案与实施步骤

方案A:控制台专用格式化路径

// Console.java改进版sendTl方法
public void sendTl(String tlKey, Object... args) {
    final String translation = tlLiteral(tlKey, args);
    if (translation.isEmpty()) return;
    
    // 控制台专用:移除MiniMessage标签后输出纯文本
    final String plainText = MiniMessage.miniMessage().stripTags(translation);
    getCommandSender().sendMessage(plainText);
}

方案B:条件化MiniMessage解析

// AdventureUtil新增方法
public static Component deserializeForSender(CommandSender sender, String text) {
    if (sender instanceof ConsoleCommandSender) {
        return Component.text(MiniMessage.miniMessage().stripTags(text));
    } else {
        return MiniMessage.miniMessage().deserialize(text);
    }
}

完整修复流程图

mermaid

验证与兼容性测试

测试用例设计

测试场景命令输入预期输出修复前修复后
基础合成配方/recipe iron_ingot无格式纯文本配方含 标签 纯文本步骤说明
多配方选择/recipe cake编号列表格式标签混杂数字清晰数字列表
无结果场景/recipe diamond_block"无配方"提示带 错误标签 纯文本错误提示

版本兼容性矩阵

Minecraft版本兼容状态特殊说明
1.18-1.20.1完全兼容需要同步更新AdventureAPI至4.14.0+
1.17及以下部分兼容需移除ParsedPlaceholder相关代码

代码优化建议与最佳实践

1. 命令输出标准化

// 推荐的命令输出模板
public void sendFormattedRecipe(CommandSender sender, Recipe recipe) {
    if (sender instanceof Player) {
        // 玩家端保留完整格式
        sender.sendTl("formatted.recipe", AdventureUtil.parsed(recipe.toString()));
    } else {
        // 控制台使用简化格式
        sender.sendTl("plain.recipe", recipe.toString());
    }
}

2. 翻译文件重构建议

# 拆分翻译键以支持双格式输出
formatted.recipe=配方: <green>{0}</green>
plain.recipe=配方: {0}

常见问题解答

Q: 为何玩家端显示正常而控制台异常?

A: 玩家客户端内置支持Minecraft格式代码(§),而控制台通常不解析ANSI转义序列,导致MiniMessage标签直接显示。

Q: 修复会影响其他命令的控制台输出吗?

A: 仅会影响使用AdventureUtil.parsed()的命令,建议对/mail/balance等涉及控制台输出的命令进行同样检查。

Q: 能否通过配置文件临时规避此问题?

A: 可在config.yml中添加临时解决方案:

# 临时规避配置
console:
  strip-formatting: true

总结与未来展望

本次分析揭示了EssentialsX在跨终端文本处理上的设计缺陷,核心问题在于未对控制台环境的格式支持能力做特殊处理。通过本文提供的两种修复方案,可彻底解决/recipe命令的格式化异常问题。

建议开发团队在后续版本中:

  1. 建立统一的命令输出抽象层
  2. 为控制台实现专用的文本格式化器
  3. 在翻译系统中引入格式标记(如{plain}{formatted}

这些改进将不仅解决当前问题,还能预防其他命令出现类似的跨终端兼容性问题,提升整体代码质量与用户体验。

【免费下载链接】Essentials The modern Essentials suite for Spigot and Paper. 【免费下载链接】Essentials 项目地址: https://gitcode.com/GitHub_Trending/es/Essentials

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值