聊天与名称显示修改(Chat & Display)¶
玩家看到的「表面功夫」——聊天消息长啥样、头顶名字是什么、Tab 列表里叫什么,都能用 KubeJS 改。这篇把三块整合成一个章节:
- 聊天消息修改:加前缀(称号/权限)、替换敏感词、拦截消息;
- 头顶名称修改:
displayName覆盖玩家名字(头顶 + Tab 列表一起变); - Tab 面板修改:Tab 列表显示的就是
displayName,改名字 = 改 Tab。
💡 这篇是「实现称号系统(29 篇)」的显示层深化——29 篇把三者用在称号上,这篇讲透原理和通用玩法。
1. 聊天消息修改¶
监听 PlayerEvents.chat,改 event.message 就能改写玩家发出的消息(改的是服务端最终广播出去的内容,全服都看到改后的)。
1.1 加前缀(称号 / 权限 / 随便什么)¶
// server_scripts/display_chat_prefix.js
PlayerEvents.chat(event => { // 监听"玩家发消息"
let player = event.player
let title = player.persistentData.title // 读玩家当前称号 id(29 篇存进去的)
if (title && title !== 'none') { // 有称号就加前缀
event.message = '§7[' + title + ']§r ' + event.message // 效果: [killer] 大家好
}
})
💡 更正式的称号显示(带颜色、查称号表)直接抄 29 篇:
event.message = title.color + '[' + title.name + ']§r ' + event.message。
1.2 替换敏感词¶
// server_scripts/display_chat_filter.js
const BAD_WORDS = ['敏感词1', '敏感词2', '敏感词3'] // 要替换的词表(服主可自己加)
PlayerEvents.chat(event => {
let msg = event.message // 先存到 let 变量里(后面要重新赋值,不能用 const)
BAD_WORDS.forEach(word => { // 遍历词表
msg = msg.replaceAll(word, '***') // 把词替换成 ***(replaceAll 替换全部)
})
event.message = msg // 写回消息
})
1.3 拦截屏蔽(不让发出去)¶
把 event.message 置空,消息就发不出来了:
// server_scripts/display_chat_block.js
PlayerEvents.chat(event => {
let msg = event.message
if (msg.includes('脏话A') || msg.includes('脏话B')) { // 命中屏蔽词
event.player.tell('§c这条消息包含违禁词,已拦截!') // 只告诉本人
event.message = '' // 置空 = 不广播(null 也可以,'' 更稳)
return
}
if (msg.startsWith('!') ) { // 以 ! 开头的当指令处理(这里只是示例拦截逻辑)
// 比如配合 29/31 篇的 !称号 !签到 指令,在别的事件里已经处理过,这里就不用管
}
})
⚠️ 拦截后玩家自己会「看到」消息已发送,但全服没人收到——想更明显可以同时
player.tell提示原因(上面的例子就是)。
1.4 只允许特定格式¶
// server_scripts/display_chat_restrict.js
PlayerEvents.chat(event => {
let msg = event.message
if (!msg.startsWith('[交易]')) { // 不允许直接喊话,必须先打 [交易] 标签
event.player.tell('§c请使用格式:[交易] <你要卖的东西>')
event.message = ''
}
})
2. 玩家头顶名称修改¶
player.displayName 是玩家的「显示名」——设置后头顶名字、Tab 列表名字、聊天里的名字都会变(原版机制)。它存在客户端显示层,服务器重启后会还原,所以要在登录事件里重新设置。
// server_scripts/display_name.js —— 头顶名称完整流程
function applyName(player) { // 封装成函数:给谁设置显示名就调谁(改称号后也调它刷新)
let title = player.persistentData.title // 读称号(没有就是 undefined)
if (!title || title === 'none') { // 没称号
player.displayName = player.username // 恢复成默认名(原版名字)
return
}
player.displayName = '§6[' + title + ']§r ' + player.username // 带称号的名字
}
PlayerEvents.loggedIn(event => { // 登录时设置一次(重启后也能恢复)
applyName(event.player)
})
// 用法:改称号后立刻刷新名字
// applyName(某玩家) // 29 篇的切换称号指令里就是这么调的
💡
displayName不影响存档、不影响指令选择器(@a还是按真实 ID 匹配),只是显示层面的花活,随便折腾。
3. Tab 面板修改¶
Tab 列表(按 Tab 键打开的那个玩家列表)显示的名字就是玩家的 displayName——所以第二节的 applyName 一改,Tab 列表同步生效,不需要额外 API。
按身份显示不同 Tab 名字的完整示例:
// server_scripts/display_tab.js —— 按身份显示不同 Tab 名字
function applyName(player) {
let data = player.persistentData
if (player.isCreative()) { // 创造模式 = 管理员(跟 29 篇管理指令同一个判断)
player.displayName = '§c★ 管理 §r' + player.username
} else if (data.vip) { // 存档里打了 vip 标记(充值/活动发的)
player.displayName = '§d✦ VIP §r' + player.username
} else if (data.title && data.title !== 'none') { // 有称号
player.displayName = '§6[' + data.title + ']§r ' + player.username
} else {
player.displayName = player.username // 普通玩家
}
}
PlayerEvents.loggedIn(event => applyName(event.player)) // 登录时刷新
💡 判断身份的三个思路:
player.isCreative()(创造=管理员,最简单)、persistentData标记(data.vip = true,可后台发)、29 篇的称号表(unlocked/title)。
Tab 面板顶部/底部文字(header/footer):KubeJS 1.20.1 没有可靠的现成 API,不建议强行实现(硬写要碰网络包,容易崩)。想要这个效果,要么等 KubeJS 更新,要么用专门的模组。名字修改这一层,上面完全够用。
4. 整合案例:一键全装¶
一个文件实现:聊天加称号前缀 + 敏感词替换 + 违禁词拦截 + 管理员特殊颜色 + 头顶/Tab 名字带身份:
// server_scripts/display.js —— 聊天与名称显示完整案例
const BAD_WORDS = ['脏话1', '脏话2'] // 屏蔽词(直接拦截)
const FILTER_WORDS = ['敏感词A', '敏感词B'] // 替换词(替换成 ***)
// —— 聊天:前缀 + 过滤 + 管理员颜色 ——
PlayerEvents.chat(event => {
let player = event.player
let msg = event.message
// 1. 拦截违禁词
if (BAD_WORDS.some(w => msg.includes(w))) {
player.tell('§c消息含违禁词,已拦截!')
event.message = ''
return
}
// 2. 替换敏感词
FILTER_WORDS.forEach(w => { msg = msg.replaceAll(w, '***') })
// 3. 加前缀:管理员红色 / 有称号用称号 / 普通玩家原样
if (player.isCreative()) {
msg = '§c[管理]§r ' + msg
} else {
let title = player.persistentData.title
if (title && title !== 'none') msg = '§6[' + title + ']§r ' + msg
}
event.message = msg
})
// —— 名字:头顶 + Tab 同步 ——
function applyName(player) {
if (player.isCreative()) {
player.displayName = '§c★ 管理 §r' + player.username
} else if (player.persistentData.vip) {
player.displayName = '§d✦ VIP §r' + player.username
} else if (player.persistentData.title && player.persistentData.title !== 'none') {
player.displayName = '§6[' + player.persistentData.title + ']§r ' + player.username
} else {
player.displayName = player.username
}
}
PlayerEvents.loggedIn(event => applyName(event.player)) // 登录刷新(重启后也能恢复)
效果:
5. 速查表¶
| 功能 | 关键代码 | 说明 |
|---|---|---|
| 聊天加前缀 | event.message = '前缀' + event.message |
PlayerEvents.chat 里改写 |
| 替换敏感词 | msg.replaceAll(word, '***') |
词表循环替换 |
| 拦截消息 | event.message = '' |
置空 = 不广播,可配 player.tell 提示 |
| 格式限制 | msg.startsWith('[交易]') 判断 |
不符合就拦截 |
| 设置头顶名 | player.displayName = 'xxx' |
同时影响头顶 + Tab + 聊天名 |
| 恢复默认名 | player.displayName = player.username |
还原原版名字 |
| 登录刷新 | PlayerEvents.loggedIn(event => applyName(event.player)) |
重启后必须重新设置 |
| 管理员判断 | player.isCreative() |
创造模式当管理员(与 29 篇一致) |
| Tab 名字 | 改 displayName 即可 |
原版机制,无需额外 API |
| Tab header/footer | ❌ 无可靠 API | 1.20.1 不建议强行实现 |
还能玩什么? 聊天颜色渐变(拼接多段 § 颜色码)、死亡播报样式(结合 09 篇事件列表找死亡事件)、称号 + 权限 + 交易分区聊天(player.server.players 遍历定向转发)——核心就是 event.message 和 displayName 两个入口,思路都是一样的。