Appearance
定位追踪
文档版本:基于 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 add | RfmTrackListCommand.add() |
| 叛节者解锁 | traitorCaptureUnlocked 变为 true | RfmHunterSystemManager 中自动调用 |
| 逃走币锁物品 | 每次使用 CoinLockItem | CoinLockItem 内联逻辑 |
架构设计
追踪数据流
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 -.->|"重新补充"| Compasstick 调度时序
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.java | track 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.java | NFA_TRACKING_COMPASS 数据组件注册 |
com/chenxi/chenxi_rfm/server/event/ServerRfmGameEvents.java | 防丢弃事件 + 玩家登录事件分发 |
关键流程
tick 循环完整流程
每 tick(ServerRfmGameEvents.onServerTick())调用 RfmLocatorManager.tick(server):
- 获取存活目标:
pruneInvalidTargets()遍历持久化列表,过滤掉非isCapturableRunner的目标并同步清理持久化 - 空列表处理:无追踪目标时
clearForAllViewers()清空所有观看者的指南针和 ActionBar,重置采样计时器 - 坐标采样(距上次采样 >= 5 秒):
sampleOnlineTargetPositions()遍历每个存活目标,获取其当前维度和blockPosition(),存入PersistentRfmLocatorSavedData.cachedPositions。离线玩家坐标不更新(保持上次缓存) - ActionBar 推送:采样时刻立即推送,随后每 10 tick 推送一次
- 遍历所有在线玩家:
isViewer()检查身份是否为 HUNTER/NPC,否则清空指南针findNearestTarget()遍历所有目标的缓存坐标,取平面距离最近的;跨维度目标距离设为Double.MAX_VALUE / 4ensureCompassAtHotbarSlot()管理快捷栏第 9 格指南针
指南针创建与占位
ensureCompassAtHotbarSlot() 执行步骤:
- 清空旧指南针:遍历背包,将第 9 格外的所有追踪指南针(通过
NFA_TRACKING_COMPASS组件识别)设为空气 - 腾出第 9 格:若第 9 格非空且非追踪指南针,先尝试
inventory.add()移到其他格,失败则drop()扔出 - 创建新指南针:
createCompass()生成带LODESTONE_TRACKER(指向目标坐标的GlobalPos)+CUSTOM_NAME("定位指南针"青色)+NFA_TRACKING_COMPASS=true的指南针 - 设置第 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 add 的 filterAliveParticipantRunners() 使用四重过滤:
- 必须是本轮参与者(
PersistentRfmRoundSavedData.getParticipantRunnerUuids()) - 身份必须是 RUNNER
RunnerState中eliminated && abstained均为 false- 若为叛节者(
traitor=true),必须traitorCaptureUnlocked=true才可被追踪
数据持久化
PersistentRfmLocatorSavedData
文件:<world>/data/nfa_rfm/rfm_locator.dat
| NBT 键 | 类型 | 说明 |
|---|---|---|
TrackedPlayers | List<Compound> | 每项含 Uuid |
CachedPositions | List<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 clear | GAME_ADMIN_PLAYER_ONLY | 清空全部追踪目标(同时清空所有观看者指南针) |
注意事项 / 限制
- 仅 HUNTER/NPC 可见:
isViewer()严格限制为 HUNTER 或 NPC 角色,其他身份(包括 RUNNER)看不到指南针和 ActionBar。 - 追踪指南针不可丢弃:丢弃事件被
ServerRfmGameEvents拦截,指南针强制占位快捷栏第 9 格。 - 跨维度不工作:跨维度距离为
Double.MAX_VALUE / 4(极大值),指南针指向可能不可靠,ActionBar 距离显示为--。 - 离线玩家坐标冻结:
sampleOnlineTargetPositions()只更新在线玩家的坐标,离线玩家的缓存坐标保持最后值。 - 自动清理失效目标:每次 tick 的
pruneInvalidTargets()会从持久化列表移除已不满足可抓捕条件的逃走者(淘汰/弃权/叛节者未解锁)。 - 指南针使用原版 LodestoneTracker 组件:坐标通过数据组件嵌入,客户端直接使用原版磁石指南针渲染,无需自定义网络包同步坐标。
- 定位追踪与警报系统独立运作:两个系统互不干扰——追踪提供持续的位置指引,警报提供周期性的声效暴露。同一玩家可同时被追踪和报警。