Skip to content

定位追踪

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

概述

定位追踪系统为猎人和工作人员提供逃走者位置的实时显示。通过追踪列表管理目标玩家,每 5 秒采样其坐标缓存,猎人和工作人员获得自动指向最近追踪目标的指南针(快捷栏第 9 格),并在 ActionBar 显示坐标与距离。系统与叛节者解锁、逃走币锁物品联动,追踪列表支持管理员手动增删和清除。


核心概念

追踪角色

角色能力
HUNTER / NPC可看到 ActionBar 坐标信息,获得定位指南针;其他角色不渲染任何定位UI
RUNNER(被追踪者)必须存活且为可抓捕逃走者(isCapturableRunner:非淘汰、非弃权、叛节者需已解锁)

两套坐标缓存

缓存所属类刷新频率用途
cachedPositions(持久化 NBT)PersistentRfmLocatorSavedData每 5 秒指南针指向 + ActionBar 坐标显示
RUNNER_POSITION_CACHE(内存 Map)RfmHunterEntityManager每 10 秒A 型猎人实体巡逻导航(本系统不涉及)

三种触发方式

方式触发条件入口代码
管理员手动/nfa rfm track list addRfmTrackListCommand.add()
叛节者解锁traitorCaptureUnlocked 变为 trueRfmHunterSystemManager 中自动调用
逃走币锁物品每次使用 CoinLockItemCoinLockItem 内联逻辑

架构设计

追踪数据流

mermaid
flowchart LR
    subgraph Trigger["触发源"]
        Admin["管理员指令<br/>track list add"]
        Traitor["叛节者解锁<br/>自动添加"]
        CoinLock["CoinLockItem<br/>交互触发"]
    end

    subgraph Manager["RfmLocatorManager(全静态)"]
        List["trackedPlayers<br/>LinkedHashSet(持久化)"]
        Filter["pruneInvalidTargets<br/>自动清理失效目标"]
        Cache["cachedPositions<br/>每5秒坐标快照"]
    end

    subgraph Output["输出端"]
        Compass["定位指南针<br/>快捷栏第9格(LodestoneTracker)"]
        ActionBar["ActionBar<br/>坐标+距离(每10tick)"]
        TossBlock["防丢弃拦截<br/>ServerRfmGameEvents"]
    end

    Trigger --> List
    List --> Filter
    Filter --> Cache
    Cache -->|"findNearestTarget 最近目标"| Compass
    Cache -->|"sendActionBar"| ActionBar
    Compass -.->|"丢弃事件拦截"| TossBlock
    TossBlock -.->|"重新补充"| Compass

tick 调度时序

mermaid
sequenceDiagram
    participant Tick as ServerTickEvent.Post
    participant LM as RfmLocatorManager.tick()
    participant Data as PersistentRfmLocatorSavedData
    participant Viewer as 观看者(HUNTER/NPC)
    participant Sound as 客户端

    Tick->>LM: tick(server)
    LM->>Data: getTrackedPlayers()
    LM->>LM: pruneInvalidTargets()
    Note over LM: 自动移除已淘汰/弃权的目标

    alt 追踪列表为空
        LM->>LM: clearForAllViewers() 清空指南针+ActionBar
    else 有追踪目标
        alt 距上次采样 >= 5秒
            LM->>LM: sampleOnlineTargetPositions()
            LM->>Data: updateCachedPosition(uuid, xyz, now)
            LM->>LM: actionBarTickCounter=0, pushActionBar=true
        else 每10tick
            LM->>LM: actionBarTickCounter++, pushActionBar=true
        end

        loop 遍历所有在线玩家
            alt 是观看者(HUNTER/NPC)
                LM->>LM: findNearestTarget(viewer) 跨维度=MAX/4
                LM->>LM: ensureCompassAtHotbarSlot(viewer, nearest)
                alt pushActionBar
                    LM->>Viewer: sendActionBar(坐标+距离)
                end
            else 非观看者
                LM->>LM: clearCompass(player)
            end
        end
    end

关键文件

核心管理

文件说明
com/chenxi/chenxi_rfm/server/rfm/RfmLocatorManager.java定位追踪核心(全静态方法,约 315 行)
com/chenxi/chenxi_rfm/server/config/rfm/PersistentRfmLocatorSavedData.java追踪列表 + 坐标缓存 NBT 持久化

指令

文件说明
com/chenxi/chenxi_rfm/server/command/rfm/RfmTrackCommand.java/nfa rfm track 节点注册
com/chenxi/chenxi_rfm/server/command/rfm/RfmTrackListCommand.javatrack list add/delete/clear 实现(含参与者过滤)

联动触发

文件说明
com/chenxi/chenxi_rfm/server/rfm/RfmHunterSystemManager.java叛节者解锁时自动添加追踪、抓捕淘汰时自动移除
com/chenxi/chenxi_rfm/server/command/rfm/RfmTraitorCommand.java叛节者指令间接触发
com/chenxi/chenxi_rfm/common/item/CoinLockItem.java逃走币锁物品使用后添加追踪
com/chenxi/chenxi_rfm/common/registry/ModDataComponents.javaNFA_TRACKING_COMPASS 数据组件注册
com/chenxi/chenxi_rfm/server/event/ServerRfmGameEvents.java防丢弃事件 + 玩家登录事件分发

关键流程

tick 循环完整流程

每 tick(ServerRfmGameEvents.onServerTick())调用 RfmLocatorManager.tick(server)

  1. 获取存活目标pruneInvalidTargets() 遍历持久化列表,过滤掉非 isCapturableRunner 的目标并同步清理持久化
  2. 空列表处理:无追踪目标时 clearForAllViewers() 清空所有观看者的指南针和 ActionBar,重置采样计时器
  3. 坐标采样(距上次采样 >= 5 秒):sampleOnlineTargetPositions() 遍历每个存活目标,获取其当前维度和 blockPosition(),存入 PersistentRfmLocatorSavedData.cachedPositions。离线玩家坐标不更新(保持上次缓存)
  4. ActionBar 推送:采样时刻立即推送,随后每 10 tick 推送一次
  5. 遍历所有在线玩家
    • isViewer() 检查身份是否为 HUNTER/NPC,否则清空指南针
    • findNearestTarget() 遍历所有目标的缓存坐标,取平面距离最近的;跨维度目标距离设为 Double.MAX_VALUE / 4
    • ensureCompassAtHotbarSlot() 管理快捷栏第 9 格指南针

指南针创建与占位

ensureCompassAtHotbarSlot() 执行步骤:

  1. 清空旧指南针:遍历背包,将第 9 格外的所有追踪指南针(通过 NFA_TRACKING_COMPASS 组件识别)设为空气
  2. 腾出第 9 格:若第 9 格非空且非追踪指南针,先尝试 inventory.add() 移到其他格,失败则 drop() 扔出
  3. 创建新指南针createCompass() 生成带 LODESTONE_TRACKER(指向目标坐标的 GlobalPos)+ CUSTOM_NAME("定位指南针"青色)+ NFA_TRACKING_COMPASS=true 的指南针
  4. 设置第 9 格 为该新指南针,发送背包同步

防丢弃机制

ServerRfmGameEvents.onItemToss() 拦截物品丢弃事件:若被丢弃物品通过 isTrackingCompass() 检测(指南针 + NFA_TRACKING_COMPASS 组件),则取消丢弃事件并调用 onTrackingCompassTossed() 重新补充指南针到快捷栏。

ActionBar 格式

  • 正常最近定位玩家坐标(x, y, z) 距离N格
  • 跨维度最近定位玩家坐标(x, y, z) 距离--格(距离显示为 --
  • LOCAL 模式:当 HUD 配置为 LOCAL 模式时,坐标会减去原点偏移:displayX = x - hudData.getOriginX()

添加时的过滤规则

/nfa rfm track list addfilterAliveParticipantRunners() 使用四重过滤:

  1. 必须是本轮参与者(PersistentRfmRoundSavedData.getParticipantRunnerUuids()
  2. 身份必须是 RUNNER
  3. RunnerStateeliminated && abstained 均为 false
  4. 若为叛节者(traitor=true),必须 traitorCaptureUnlocked=true 才可被追踪

数据持久化

PersistentRfmLocatorSavedData

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

NBT 键类型说明
TrackedPlayersList<Compound>每项含 Uuid
CachedPositionsList<Compound>每项含 Uuid + Dimension + X/Y/Z + SyncMillis

自动清理pruneInvalidTargets() 在每次 tick 时自动移除失效目标(淘汰/弃权/叛节者未解锁),并同步 setDirty()


指令

指令权限说明
/nfa rfm track list add <players>GAME_ADMIN_PLAYER_ONLY添加追踪目标(自动过滤非存活逃走者)
/nfa rfm track list delete <players>GAME_ADMIN_PLAYER_ONLY移除追踪目标
/nfa rfm track list clearGAME_ADMIN_PLAYER_ONLY清空全部追踪目标(同时清空所有观看者指南针)

注意事项 / 限制

  1. 仅 HUNTER/NPC 可见isViewer() 严格限制为 HUNTER 或 NPC 角色,其他身份(包括 RUNNER)看不到指南针和 ActionBar。
  2. 追踪指南针不可丢弃:丢弃事件被 ServerRfmGameEvents 拦截,指南针强制占位快捷栏第 9 格。
  3. 跨维度不工作:跨维度距离为 Double.MAX_VALUE / 4(极大值),指南针指向可能不可靠,ActionBar 距离显示为 --
  4. 离线玩家坐标冻结sampleOnlineTargetPositions() 只更新在线玩家的坐标,离线玩家的缓存坐标保持最后值。
  5. 自动清理失效目标:每次 tick 的 pruneInvalidTargets() 会从持久化列表移除已不满足可抓捕条件的逃走者(淘汰/弃权/叛节者未解锁)。
  6. 指南针使用原版 LodestoneTracker 组件:坐标通过数据组件嵌入,客户端直接使用原版磁石指南针渲染,无需自定义网络包同步坐标。
  7. 定位追踪与警报系统独立运作:两个系统互不干扰——追踪提供持续的位置指引,警报提供周期性的声效暴露。同一玩家可同时被追踪和报警。

相关文档