Appearance
警报系统
文档版本:基于 2026-06-01 代码分析
概述
警报系统负责在特定玩家位置周期性播放警报音效,暴露其所在位置。支持两种警报管理模型:列表管理(管理员通过指令设置警报列表,启动后定时响铃)和侦测管理(侦测方块检测到进入范围的逃走者,自动开始警报)。
警报音效以 1.5 倍音量按RECORDS分类播放,每 2 秒循环一次,形成持续的"暴露"压力。
核心概念
两种管理模型
| 属性 | 列表管理(listManaged) | 侦测管理(detectManaged) |
|---|---|---|
| 触发方式 | 指令 /nfa rfm alarm start | 侦测方块自动检测 |
| 持续时间 | 有时间限制(指令指定) | Long.MAX_VALUE(永不超时) |
| 持久化列表 | 受列表控制(tick时反向检查) | 不受列表控制 |
| 玩家淘汰时 | 自动从列表和活动任务中移除 | 仅从活动任务中移除 |
| 停止方式 | 指令停止 / 超时 / 淘汰 | 离开侦测范围 / 淘汰 |
循环参数
- 间隔:
LOOP_INTERVAL_MILLIS = 2000(每 2 秒播放一次) - 音量:
ALARM_VOLUME = 1.5(24.0F / 16.0F) - 音效分类:
SoundSource.RECORDS(强制覆盖普通音量限制)
架构设计
警报生命周期
mermaid
sequenceDiagram
participant Admin as 管理员
participant Cmd as 命令
participant AM as RfmAlarmManager
participant Data as PersistentRfmAlarmSavedData
participant Task as AlarmLoopTask
participant Sound as 音效系统
Admin->>Cmd: /nfa rfm alarm list add @p
Cmd->>AM: addToList(targets)
AM->>Data: addPlayers(uuids)
Admin->>Cmd: /nfa rfm alarm start 1 30
Cmd->>AM: startFromList(server, 90)
AM->>AM: 清空 ACTIVE_ALARMS
AM->>Data: 获取持久化列表
loop 每个存活逃走者
AM->>Task: 创建 listManaged(endAt=now+90000)
end
loop tick() 每tick
AM->>Task: 检查超时/列表一致性/玩家存活
alt 每2秒
AM->>Sound: playAlarmAround(target)
Note over Sound: 目标位置播放 alarm.ogg<br/>音量1.5 × RECORDS分类
end
alt 玩家淘汰
AM->>Data: 自动从列表移除
AM->>Task: 移除任务
end
end
Note over Task: 超时 → 任务移除
Note over Cmd: /nfa rfm alarm stop → 全部清空两种模型的任务并存
ACTIVE_ALARMS 是一个共享的 LinkedHashMap<UUID, AlarmLoopTask>,同时容纳 listManaged 和 detectManaged 两种任务。同一个玩家可能同时有列表警报和侦测警报(但 UUID 唯一,后创建的会覆盖先前的)。
关键文件
| 文件 | 说明 |
|---|---|
com/chenxi/chenxi_rfm/server/rfm/RfmAlarmManager.java | 警报管理核心(含 AlarmLoopTask) |
com/chenxi/chenxi_rfm/server/config/rfm/PersistentRfmAlarmSavedData.java | 警报列表持久化 |
com/chenxi/chenxi_rfm/server/rfm/RfmDetectBlockManager.java | 侦测方块联动(startDetectAlarm/stopDetectAlarm) |
com/chenxi/chenxi_rfm/server/command/rfm/RfmAlarmCommand.java | /nfa rfm alarm 入口 |
com/chenxi/chenxi_rfm/server/command/rfm/RfmAlarmStartCommand.java | alarm start |
com/chenxi/chenxi_rfm/server/command/rfm/RfmAlarmStopCommand.java | alarm stop |
com/chenxi/chenxi_rfm/server/command/rfm/RfmAlarmListCommand.java | alarm list add/delete/clear |
com/chenxi/chenxi_rfm/common/registry/ModSounds.java | ALARM 音效注册 |
com/chenxi/chenxi_rfm/server/event/ServerRfmGameEvents.java | tick 调度入口 |
关键流程
添加玩家到列表
/nfa rfm alarm list add <targets>:
- 选择在线玩家
- 如果选择了所有在线玩家(
@a) → 要求confirm二次确认(命令方块除外) @a时自动过滤为"存活的逃走者"(filterAliveRunners)- 非全选时直接按传入的玩家集合添加,不做存活过滤
启动警报
/nfa rfm alarm start <minutes> <seconds>:
- 清空
ACTIVE_ALARMS - 计算
endAt = now + totalSeconds * 1000 - 遍历持久化列表中所有玩家,仅为存活逃走者创建
listManaged任务 - 提示实际启动的警报数量
tick 循环
每 tick 执行:
- 遍历
ACTIVE_ALARMS的所有条目 - 超时检查:
now >= endAtMillis→ 移除 - 列表一致性检查:
listManaged但目标已不在持久化列表 → 移除 - 存活检查:玩家不存活 → 如果是
listManaged则同步从持久化列表删除,移除任务 - 间隔检查:
nextPlayMillis > now→ 跳过 - 播放音效:
playAlarmAround(server, targetUuid),失败(玩家下线)→ 移除 - 设置下次播放时间:
nextPlayMillis = now + 2000
侦测方块联动
startDetectAlarm(uuid)→ 创建detectManaged任务(endAtMillis=Long.MAX_VALUE, nextPlayMillis=0立即播放)stopDetectAlarm(uuid)→ 从ACTIVE_ALARMS移除
数据持久化
PersistentRfmAlarmSavedData
文件:<world>/data/nfa_rfm/rfm_alarm.dat
json
{
"Players": [
{ "Uuid": "uuid-1" },
{ "Uuid": "uuid-2" }
]
}- 仅存储目标 UUID 列表,不存储任务状态
- 任务运行时状态(超时、下次播放时间、管理类型)全在内存中的
ACTIVE_ALARMS setDirty()标记持久化,在 Minecraft 自动保存时写入
注意事项 / 限制
- 不跨维度:音效仅在目标玩家所在维度播放,其他维度的玩家听不到。
- 距离衰减有效:
playSound(null, x, y, z, ...)的 null 接收者意味着所有玩家都能听到,但受 Minecraft 原生的声音距离衰减影响。 - 1.5倍音量:通过
RECORDS分类 + 高音量设计确保可听性。 - 主动移除淘汰者:tick 中自动检测玩家是否存活,不存活则同步清理持久化列表和活动任务。
- listManaged 的一致性校验:tick 中会检查目标是否仍在持久化列表中,防止数据不一致。
- detectManaged 不受列表管理:侦测触发的警报不检查持久化列表一致性。
- 全选时自动过滤:
@a全选时会自动过滤为存活逃走者;需要添加所有玩家时需逐个指定。