Skip to content

玩家身份与状态

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

概述

玩家身份与状态系统管理逃走中MOD所有玩家的角色身份(Runner/Hunter/NPC)和运行时状态(淘汰/弃权/叛节者/可抓捕等)。通过 RfmPlayerIdentityManager 统一管理身份变更,PlayerStateStore 独立存储运行时状态,与权限系统完全解耦。


核心概念

三方角色

角色枚举值含义
RUNNERrunner逃走者——躲避猎人追捕,赚取逃走币
HUNTERhunter猎人——追捕逃走者,获得淘汰奖励
NPCnpc工作人员——不参与抓捕,不可被抓

逃走者子状态(RunnerState)

字段默认值含义
eliminatedfalse已被淘汰出局
abstainedfalse已弃权
traitorfalse叛节者
traitorCaptureUnlockedfalse叛节者可被猎人抓捕

互斥规则

  • eliminatedabstained 互斥(设为 true 时自动将另一方设为 false)
  • traitorCaptureUnlocked 仅在 traitor == true 时生效

猎人状态(HunterState)

字段默认值含义
catchabletrue是否可被抓(被逃走者反击)
typeNORMAL猎人类型:NORMALINVISIBLE(潜行时隐身)

架构设计

身份与状态分离

mermaid
graph TB
    subgraph Identity["PersistentRfmPlayerIdentitySavedData<br/>身份持久化 (nfa_rfm/rfm_player_identity.dat)"]
        ID_RECORD["PlayerIdentityRecord<br/>uuid · originalName · nickname · role"]
    end

    subgraph State["PlayerStateStore<br/>状态持久化 (nfa_rfm/rfm_player_state.dat)"]
        RUNNER["RunnerState<br/>eliminated · abstained<br/>traitor · traitorCaptureUnlocked"]
        HUNTER["HunterState<br/>catchable · type"]
        CAPTURE["canCapture · canBeCaptured"]
    end

    subgraph Manager["RfmPlayerIdentityManager<br/>身份管理核心门面"]
        SET_ROLE["setRole()"]
        GET_DISPLAY["getDisplayName()"]
        SYNC["syncAndApply()"]
    end

    Identity --> Manager
    State --> Manager
    Manager --> SET_ROLE
    Manager --> GET_DISPLAY
    Manager --> SYNC

角色切换时的状态重置

mermaid
flowchart TD
    A[setRole server, uuid, originalName, role] --> B{角色是否变化?}
    B -->|否| C[跳过状态重置]
    B -->|是| D[onRoleChanged]
    D --> E[重置 RunnerState<br/>全部字段=false]
    D --> F[重置 HunterState<br/>catchable=true]
    D --> G{新角色?}
    G -->|HUNTER| H[canCapture=true<br/>canBeCaptured=false]
    G -->|RUNNER| I[canCapture=false<br/>canBeCaptured=true]
    G -->|NPC| J[canCapture=false<br/>canBeCaptured=false]
    H --> K[syncAndApply<br/>更新Scoreboard队伍<br/>刷新通知目标]
    I --> K
    J --> K

关键文件

文件说明
com/chenxi/chenxi_rfm/common/rfm/player/RfmPlayerRole.java角色枚举(RUNNER/HUNTER/NPC)
com/chenxi/chenxi_rfm/server/rfm/RfmPlayerIdentityManager.java身份管理核心门面
com/chenxi/chenxi_rfm/server/config/rfm/PersistentRfmPlayerIdentitySavedData.java身份持久化(PlayerIdentityRecord)
com/chenxi/chenxi_rfm/server/config/rfm/PlayerStateStore.java状态持久化(RunnerState + HunterState)
com/chenxi/chenxi_rfm/server/rfm/RfmPlayerTeamService.javaScoreboard 队伍映射
com/chenxi/chenxi_rfm/server/rfm/RfmHunterTypeService.java猎人隐身类型特效
com/chenxi/chenxi_rfm/server/command/rfm/RfmIdentityCommand.java/nfa rfm identity 指令

关键流程

显示名解析

getDisplayName(record):
  if nickname 非空 → 返回 nickname
  else → 返回 originalName(Minecraft 原始用户名)

昵称最大 16 个字符宽度(ASCII 计 1,非 ASCII 计 2),过滤控制字符。

Scoreboard 队伍映射

角色+状态队伍名前缀颜色
RUNNER + 存活nfa_runner_alive[逃走者]绿色
RUNNER + eliminatednfa_runner_out[出局]灰色
RUNNER + abstainednfa_runner_abstain[弃权]黄色
HUNTERnfa_hunter[猎人]黑色
NPCnfa_npc[工作人员]金色

旧版数据迁移

ServerStartedEvent 时触发 migrateLegacyDataIfNeeded()

旧版 identity.dat (NBT)
    ├── 状态字段迁移 → PlayerStateStore (rfm_player_state.dat)
    │     RunnerEliminated  → RunnerState.eliminated
    │     RunnerAbstained   → RunnerState.abstained
    │     Traitor           → RunnerState.traitor
    │     TraitorCaptureUnlocked → RunnerState.traitorCaptureUnlocked
    │     HunterCatchable   → HunterState.catchable

    └── 权限字段迁移 → PersistentNfaPermissionSavedData
          Permission(true)  → GAME_ADMIN
          Permission(false) → 不存储(默认PLAYER)

身份变更后的同步链

  1. setRole()onRoleChanged() → 重置所有状态
  2. syncAndApply()RfmPlayerTeamService.applyPlayerTeam() + refreshAllPlayers() + RfmNoticeManager.syncNoticeTargetsToManagers()
  3. 指令末尾:RfmGameSessionManager.syncToAll() + RfmHudSyncManager.syncToAll()

数据持久化

PlayerIdentityRecord

json
{
  "Players": [
    {
      "Uuid": "550e8400-...",
      "OriginalName": "Steve",
      "Nickname": "逃跑者A",
      "Role": "runner"
    }
  ]
}

PlayerStateStore

json
{
  "RunnerStates": [
    { "Uuid": "...", "Eliminated": false, "Abstained": false, "Traitor": false, "TraitorCaptureUnlocked": false }
  ],
  "HunterStates": [
    { "Uuid": "...", "Catchable": true, "Type": "NORMAL" }
  ],
  "CanCapture": [{ "Uuid": "...", "Value": true }],
  "CanBeCaptured": [{ "Uuid": "...", "Value": true }]
}

注意事项 / 限制

  1. 身份与权限解耦setRole() 不会自动变更权限等级。权限由独立的 NfaPermissionService 管理。
  2. 旧版数据迁移幂等:迁移通过检测旧 NBT 字段存在性判断是否已迁移,不会重复执行。
  3. 显示名唯一性不强制:系统不强制昵称唯一,建议管理员通过中控面板手动检查。
  4. 团队切换即生效applyPlayerTeam() 调用后玩家在 TAB 列表的名称颜色和前缀立即更新。
  5. role 默认值为 null:未设置身份的玩家 rolenull,系统将其等同于 RUNNER 处理。

相关文档