Appearance
通知系统
文档版本:基于 2026-06-01 代码分析
概述
通知系统负责在逃走中游戏中向特定玩家群体推送消息。通知模板由管理员在中控面板创建,支持按接收者类型(全部/存活逃走者/已淘汰/猎人/工作人员/额外指定)过滤目标,通过 notice_sender 方块或中控面板手动触发发送。通知以红色标题卡片形式出现在玩家手机的"逃走中APP"页面,同时播放三次响铃音效。
核心概念
两层通知模型
| 概念 | 类 | 用途 |
|---|---|---|
| 通知模板 | NoticeRecord → RfmNoticeData | 管理员创建的模板,定义"谁该收到什么" |
| 手机通知 | RfmPhoneNoticeData | 实际推送到玩家手机的消息实例 |
转换链路:一个 RfmNoticeData 模板 → 按接收者类型解析目标 → 为每个目标生成一个 RfmPhoneNoticeData → 推送。
接收者类型
| 枚举值 | 含义 | 过滤规则 |
|---|---|---|
ALL | 全部玩家 | 所有在线的玩家身份记录 |
RUNNER_ALIVE | 存活逃走者 | role=="runner" && !eliminated && !abstained |
RUNNER_OUT | 已淘汰逃走者 | role=="runner" && eliminated |
HUNTER | 猎人 | role=="hunter" |
NPC | 工作人员 | role=="npc" |
EXTRA | 额外指定 | 仅从 extraReceivers 列表按UUID/名称解析 |
额外接收者叠加:不论主接收者类型是什么,extraReceivers 列表中的目标总是被追加。
架构设计
通知发送时序
mermaid
sequenceDiagram
participant Trigger as 触发源
participant NM as RfmNoticeManager
participant Data as PersistentRfmNoticeSavedData
participant AS as RfmAppNotificationService
participant Phone as PersistentRfmPhoneNoticesSavedData
participant Client as 玩家手机
Trigger->>NM: sendNoticeWithResult(server, noticeId)
Note over Trigger: 三种触发方式:<br/>A.中控面板GUI点击发送<br/>B.notice_sender红石上升沿<br/>C.notice_sender右键→中控面板
NM->>Data: findById(noticeId)
Data-->>NM: NoticeRecord(name, content, receiverType, extraReceivers)
NM->>NM: resolveTargets(server, record)
Note over NM: 1.获取所有在线玩家身份记录<br/>2.按receiverType过滤<br/>3.叠加extraReceivers<br/>4.仅保留在线玩家
NM->>AS: notifyPlayers(server, targets, name, content)
loop 为每个targetUuid
AS->>Phone: append(ownerUuid, title, content)
AS->>Client: AppendPhoneRfmNoticePayload
AS->>AS: scheduleRingBurst(targetUuid, 3)
Note over AS: 安排3次铃声播放(间隔2秒)
end
Client->>Client: 渲染卡片式通知中控面板同步流程
mermaid
sequenceDiagram
participant GUI as RfmManagerNoticePage
participant Client as 客户端
participant Server as 服务端
participant NM as RfmNoticeManager
participant Data as PersistentRfmNoticeSavedData
GUI->>Client: onOpen()
Client->>Server: RequestRfmNoticesPayload
Client->>Server: RequestRfmNoticeTargetsPayload
Server->>NM: syncToPlayer(player)
NM->>Data: list() 获取全部模板
Server->>Client: SyncRfmNoticesPayload
Server->>NM: syncNoticeTargetsToPlayer(player)
NM->>NM: 构建所有在线runner目标列表
Server->>Client: SyncRfmNoticeTargetsPayload
Client->>GUI: 渲染通知列表+目标列表关键文件
| 文件 | 说明 |
|---|---|
com/chenxi/chenxi_rfm/server/rfm/RfmNoticeManager.java | 通知管理核心 |
com/chenxi/chenxi_rfm/server/rfm/RfmAppNotificationService.java | 手机通知推送服务 |
com/chenxi/chenxi_rfm/server/config/rfm/PersistentRfmNoticeSavedData.java | 通知模板持久化 |
com/chenxi/chenxi_rfm/server/config/rfm/PersistentRfmPhoneNoticesSavedData.java | 手机通知持久化 |
com/chenxi/chenxi_rfm/common/rfm/notice/RfmNoticeReceiverType.java | 接收者类型枚举 |
com/chenxi/chenxi_rfm/common/block/NoticeSenderBlock.java | 通知发送器方块 |
com/chenxi/chenxi_rfm/common/block/NoticeSenderBlockEntity.java | 方块实体(绑定+红石触发) |
com/chenxi/chenxi_rfm/common/rfm/notice/RfmNoticeVariableType.java | 变量类型枚举(预留设施) |
com/chenxi/chenxi_rfm/server/command/rfm/RfmNoticeCommand.java | /nfa rfm notice clear |
关键流程
三种触发方式
| 方式 | 触发条件 | 入口 |
|---|---|---|
| 中控面板 | 管理员在通知标签页点击"发送" | RfmPayloadHandler.handleUpdateRfmNotice(ACTION_SEND) |
| 红石信号 | notice_sender 方块收到红石上升沿 | NoticeSenderBlockEntity.serverTick() |
| 右键+发送 | 管理员右键 notice_sender → 中控面板 → 手动发送 | 同上路径A |
NoticeSender 方块特性
- 方块属性:
POWERED(BooleanProperty),由红石信号控制 - 右键交互:需 GAME_ADMIN 权限,打开发送面板并自动选中已绑定的通知
- 红石触发:
POWERED=true且triggered=false时发送,设triggered=true防重复 POWERED=false时重置triggered=false,允许下一次触发- 绑定信息持久化在 BlockEntity 的 NBT 中
变量替换机制
当前状态:变量替换尚未实际实现。虽然 RfmNoticeVariableType(TEXT/PLAYER)和 RfmNoticeVariableData 已定义,但整个发送链路中没有字符串替换引擎。如果在通知内容中使用 {player_name} 占位符,它将作为字面文本发送到客户端。
数据持久化
PersistentRfmNoticeSavedData
文件:<world>/data/nfa_rfm/rfm_notice.dat
json
{
"Notices": [
{
"Id": "uuid-string",
"Name": "任务通知",
"Content": "请前往坐标点A集合",
"ReceiverType": "runner_alive",
"ExtraReceivers": ["uuid1", "uuid2"]
}
]
}PersistentRfmPhoneNoticesSavedData
文件:<world>/data/nfa_rfm/rfm_phone_notices.dat
json
{
"Notices": [
{
"Owner": "player-uuid",
"Title": "任务通知",
"Content": "请前往坐标点A集合",
"TitleColor": 16777215,
"TitleBold": 1,
"Timestamp": 1748700000000
}
]
}注意事项 / 限制
- 变量替换未实现:通知内容中的
{player_name}等变量不会被自动替换,目前按原样发送。 - 不支持删除单条手机通知:
PersistentRfmPhoneNoticesSavedData仅支持append()和clearAll()。 - 铃声仅播放3次:
scheduleRingBurst(targetUuid, 3)安排3次铃声,间隔由PhoneServerSoundScheduler管理。 - notice_sender 需红石复位:触发后将
triggered=true,需要红石信号先变为 false 才能再次触发。 - EXTRA 类型的额外性:
EXTRA作为主接收者类型时不会自动匹配任何玩家,完全依赖extraReceivers。