解决EssentialsX中/nick颜色代码破坏经济消息格式的完整方案

解决EssentialsX中/nick颜色代码破坏经济消息格式的完整方案

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

问题现象与技术背景

当玩家使用/nick命令设置带有颜色代码的昵称后,经济相关消息(如/balance查询结果)出现格式错乱。典型表现为货币数值被错误染色、数字与玩家名重叠,或聊天窗口出现无意义字符。这一问题在EssentialsX 2.19.0+版本中尤为突出,根源在于昵称颜色代码未被正确隔离,导致格式化函数解析异常。

mermaid

核心代码路径分析

1. 昵称处理机制

Commandnick.java中,昵称设置通过formatString()应用颜色代码转换:

// 应用权限检查并格式化昵称
final String newNick = user == null ? FormatUtil.replaceFormat(nick) : 
                      FormatUtil.formatString(user, "essentials.nick", nick);

changeDisplayNametrue时(默认配置),玩家的displayName会直接嵌入颜色代码,而非原始文本。

2. 经济消息构造流程

Commandbalance.java中的消息发送逻辑存在设计缺陷:

// 未过滤颜色代码直接拼接
sender.sendTl("balanceOther", target.getDisplayName(), 
             AdventureUtil.parsed(NumberUtil.displayCurrency(target.getMoney(), ess)));

target.getDisplayName()返回包含颜色代码的字符串(如§cSteve),与货币格式化结果直接拼接后,破坏了整体消息结构。

问题复现与环境验证

必要条件

  • 服务器配置:change-displayname: true(默认开启)
  • 玩家权限:essentials.nick.changecolors
  • 操作步骤:
    1. 执行/nick &6Admin设置金色昵称
    2. 其他玩家执行/balance Admin查看余额

预期结果

Admin的余额: $100.00

实际结果

§6Admin的余额: $§6100.00  // 货币数值被错误染色

深层技术原因

1. 颜色代码渗透

Minecraft使用§作为颜色代码前缀,但EssentialsX的NumberUtil.displayCurrency()未对输入文本进行净化:

// NumberUtil.java 未处理颜色代码
public static String displayCurrency(BigDecimal value, IEssentials ess) {
    return new DecimalFormat(ess.getSettings().getCurrencyFormat()).format(value);
}

2. 配置连锁效应

config.yml中的关键设置形成冲突链:

change-displayname: true      # 使用带颜色的displayName
nickname-prefix: '~'          # 前缀与颜色代码叠加
ignore-colors-in-max-nick-length: false  # 颜色代码占用字符长度

解决方案与实施指南

方案A:紧急规避措施(无需重启)

  1. 临时禁用颜色昵称权限:
/mangoperms user <player> revoke essentials.nick.changecolors
  1. 批量重置异常昵称:
/essentials:essentials reset nick all

方案B:配置优化(推荐)

修改config.yml关键参数:

change-displayname: false        # 禁用带格式的显示名
ignore-colors-in-max-nick-length: true  # 忽略颜色代码的长度计算
allowed-nicks-regex: '^[a-zA-Z0-9_]+$'  # 禁止特殊字符

执行/essentials reload使配置生效。

方案C:代码修复(开发环境)

  1. 在经济消息中剥离颜色代码:
// Commandbalance.java 修复示例
String cleanName = FormatUtil.stripFormat(target.getDisplayName());
sender.sendTl("balanceOther", cleanName, 
             AdventureUtil.parsed(NumberUtil.displayCurrency(target.getMoney(), ess)));
  1. 添加货币格式化防御处理:
// NumberUtil.java 增强
public static String displayCurrency(BigDecimal value, IEssentials ess) {
    String raw = new DecimalFormat(ess.getSettings().getCurrencyFormat()).format(value);
    return FormatUtil.stripFormat(raw);  // 确保数值无格式污染
}

效果验证与兼容性测试

验证矩阵

测试场景预期结果自动化测试用例
带颜色昵称的余额查询玩家名去色,货币格式正常BalanceFormatTest#testColoredNick
超长昵称(含颜色代码)截断时忽略颜色字符NicknameTest#testColorLength
权限不足的颜色设置自动过滤颜色代码NickCommandTest#testNoColorPerm

版本兼容性

  • ✅ 2.19.2 ~ 2.20.1:直接应用配置方案B
  • ⚠️ 2.18.x及以下:需额外修改FormatUtil.javastripFormat实现

长期防护策略

1. 代码层面

  • 实现SafeDisplayName工具类,统一处理显示名净化
  • 为消息模板添加参数类型标记(如{displayName!clean}

2. 配置层面

新增防御性配置项:

# 建议新增的安全配置
message-sanitization:
  strip-colors-from-economy: true
  max-formatted-nick-length: 20

3. 权限层面

细化颜色使用权限:

# 安全的权限分配
essentials.nick.changecolors: false  # 全局禁用颜色昵称
essentials.nick.changecolors.vip: true  # VIP用户有限开放

问题排查工具包

1. 显示名调试命令

// 临时添加到Commandessentials.java
sender.sendMessage("Raw name: " + target.getName());
sender.sendMessage("Display name: " + target.getDisplayName());
sender.sendMessage("Clean name: " + FormatUtil.stripFormat(target.getDisplayName()));

2. 颜色代码检测器

# 服务器控制台执行
essentials:debug format "§6TestName"

输出:

Original: §6TestName
Stripped: TestName
Length (raw): 8
Length (clean): 8

总结与最佳实践

EssentialsX的昵称颜色与消息格式化冲突本质上是数据边界未隔离导致的典型问题。推荐采用"三明治防御模式":

  1. 输入过滤:严格验证昵称格式(allowed-nicks-regex
  2. 处理隔离:业务逻辑中使用原始名称,展示层单独处理格式化
  3. 输出净化:所有玩家可见文本必须通过stripFormat()净化

mermaid

【免费下载链接】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、付费专栏及课程。

余额充值