Skip to content

侦测方块

文档版本:基于 2026-06-01 代码分析

概述

侦测方块系统是逃走中MOD的一个子玩法:在地图中放置侦测方块,游戏开始后这些方块成为"监控点"。当存活的逃走者进入侦测方块的范围内时,该逃走者会被标记为"被侦测到",播放响铃警报暴露其位置。

系统包含完整的生命周期:方块注册 → 快照锁定 → 激活侦测 → 破坏(扩大范围)→ 警报联动。通过破坏侦测方块可动态扩大侦测范围(+3格/个)。


核心概念

范围计算公式

当前范围 = base_range + destroyedCount × 3
  • base_range:基础侦测范围,通过 /nfa rfm detect range <1-512> 配置,默认 50 格
  • destroyedCount:本局通过 destroy 指令破坏的侦测方块数量
  • 每破坏一个侦测方块,范围增加 3 格

距离计算:使用二维欧几里得距离(忽略 Y 轴):

distance² = (playerX - blockX-0.5)² + (playerZ - blockZ-0.5)²

distance² <= range²,则玩家进入侦测范围。


架构设计

完整生命周期

mermaid
flowchart TD
    A[方块放置] -->|"serverTick 每20tick"| B[registerPlacedBlock<br/>加入 registeredBlocks]
    B --> C{指令: detect start}
    C -->|"activateSnapshot()"| D[快照 registeredBlocks → activeBlocks<br/>enabled=true, destroyedCount=0]

    D --> E["tick 每5tick 循环检测"]
    E --> F{玩家在范围内?}
    F -->|"是 且 首次进入"| G["startDetectAlarm()<br/>警报播放"]
    F -->|否| H["stopDetectAlarm()<br/>停止警报"]

    I[指令: detect destroy pos] -->|"destroyActiveBlock()"| J[从 activeBlocks 移除<br/>destroyedCount++<br/>范围+3]

    K[指令: detect stop] -->|"deactivate()"| L[enabled=false<br/>清空activeBlocks<br/>reset destroyedCount]

侦测与警报联动

mermaid
sequenceDiagram
    participant Tick as RfmDetectBlockManager.tick()
    participant Active as activeBlocks(快照方块)
    participant Player as 在线逃走者
    participant Alarm as RfmAlarmManager

    Tick->>Active: 遍历所有活跃方块
    Tick->>Player: 遍历所有存活参战逃走者

    loop 检查每个玩家
        Tick->>Tick: 计算二维距离² vs range²
        alt 在范围内 且 不在报警集合中
            Tick->>Alarm: startDetectAlarm(uuid)
            Note over Alarm: 创建 detectManaged 任务<br/>永不超时,立即播放
        else 在范围内 但已在报警
            Tick->>Tick: 跳过(已在报警)
        else 不在范围内 且在报警集合中
            Tick->>Alarm: stopDetectAlarm(uuid)
        end
    end

关键文件

文件说明
com/chenxi/chenxi_rfm/common/block/DetectBlock.java侦测方块类
com/chenxi/chenxi_rfm/common/block/DetectBlockEntity.java方块实体(serverTick 注册)
com/chenxi/chenxi_rfm/server/rfm/RfmDetectBlockManager.java侦测管理核心(tick/注册/快照/破坏)
com/chenxi/chenxi_rfm/server/config/rfm/PersistentRfmDetectSavedData.java持久化存储
com/chenxi/chenxi_rfm/server/rfm/RfmAlarmManager.java警报联动(startDetectAlarm/stopDetectAlarm)
com/chenxi/chenxi_rfm/server/config/rfm/RfmServerConfigStore.javabase_range 配置
com/chenxi/chenxi_rfm/server/command/rfm/RfmDetectCommand.java/nfa rfm detect 入口
com/chenxi/chenxi_rfm/server/command/rfm/RfmDetectStartCommand.javadetect start
com/chenxi/chenxi_rfm/server/command/rfm/RfmDetectStopCommand.javadetect stop
com/chenxi/chenxi_rfm/server/command/rfm/RfmDetectRangeCommand.javadetect range
com/chenxi/chenxi_rfm/server/command/rfm/RfmDetectStatusCommand.javadetect status
com/chenxi/chenxi_rfm/server/command/rfm/RfmDetectDestroyCommand.javadetect destroy

关键流程

方块注册

  • DetectBlockEntity.serverTick() 每秒执行一次
  • 调用 RfmDetectBlockManager.registerPlacedBlock(level, pos)
  • 将位置(维度 + x/y/z)加入 PersistentRfmDetectSavedData.registeredBlocks
  • 同一位置重复注册无害LinkedHashSet.add 幂等)

快照锁定(start)

/nfa rfm detect start 调用 activateSnapshot()

  1. 清空 activeBlocks
  2. registeredBlocks 全部复制到 activeBlocks
  3. destroyedCount = 0
  4. enabled = !activeBlocks.isEmpty()

关键:start 之后新放置的侦测方块不会自动加入快照(需要重新 start)。

破坏检测(destroy)

/nfa rfm detect destroy <pos>

  1. 验证方块是 DetectBlock
  2. 验证方块在 activeBlocks
  3. 双重确认方块仍在原位
  4. activeBlocksregisteredBlocks 中移除
  5. destroyedCount++
  6. 世界中方块设为 Blocks.AIR
  7. activeBlocks 变为空 → enabled=false, destroyedCount=0

自然破坏 vs 指令破坏

方式触发destroyedCount范围增加
指令 destroy管理员执行+1+3格
自然挖掉onRemove()不变不变

自然挖掉仅从 registeredBlocksactiveBlocks 移除,不计入破坏数。


数据持久化

PersistentRfmDetectSavedData

文件:<world>/data/nfa_rfm/rfm_detect.dat

字段类型说明
registeredBlocksLinkedHashSet<DetectBlockRecord>所有已登记的侦测方块
activeBlocksLinkedHashSet<DetectBlockRecord>快照(start时的副本)
enabledboolean是否启用
destroyedCountint已破坏数量

DetectBlockRecord(String dimension, int x, int y, int z) record。


注意事项 / 限制

  1. Y轴忽略:侦测范围为二维(XZ平面),Y轴高度不影响检测结果。
  2. 仅侦测存活的参战逃走者:被淘汰、弃权、叛节者不在侦测范围内。
  3. 警报不自动停止:侦测触发的警报(detectManaged)永不超时(endAtMillis = Long.MAX_VALUE),仅当玩家离开范围时才停止。
  4. 快照在 start 时固定:start 之后新放置的方块不参与侦测,需重新 start。
  5. enabled=false 时清空报警:tick 中若 !enabled,会调用 stopAlarmsForAllActivePlayers()

相关文档