Skip to content

电话核心

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

概述

电话核心系统为逃走中MOD提供完整的语音通话功能。玩家通过手机物品注册获取唯一号码,可拨打其他玩家进行语音通话。系统基于 Simple Voice Chat API 实现语音桥接,支持号码转发路由、通话超时控制和铃声调度。


核心概念

号码生成

号码是确定性的——以玩家 UUID 的 leastSigBits ^ mostSigBits 为种子,生成 XXX-XXX-XXX 格式(9位数字带连字符)。同一 UUID 始终生成相同号码。

通话状态机

mermaid
stateDiagram-v2
    [*] --> outgoing_ringing : 主叫拨号
    [*] --> incoming_ringing : 被叫收到来电
    [*] --> dialing_failed_pending : 空号/无效号码
    outgoing_ringing --> active : 被叫接听
    incoming_ringing --> active : 被叫接听
    outgoing_ringing --> ended : 超时/挂断
    incoming_ringing --> ended : 超时/挂断
    active --> ended : 挂断/超时
    dialing_failed_pending --> failed : 暂挂期结束
    ended --> [*]
    failed --> [*]

三个超时参数

参数默认值说明
call_wait_seconds30响铃等待秒数
max_call_seconds60最大通话秒数
message_cooldown_seconds5消息冷却(见消息系统)

架构设计

通话生命周期

mermaid
sequenceDiagram
    participant Caller as 主叫方
    participant Session as PhoneCallSessionManager
    participant Sound as PhoneServerSoundScheduler
    participant Voice as PhoneCallVoiceBridge
    participant Callee as 被叫方

    Caller->>Session: startCall(caller, targetNumber)
    Session->>Session: 号码解析+查重忙
    Session->>Sound: startIncomingRingLoop(callId, calleeUuid)
    Session->>Callee: SyncPhoneCallStatePayload(ringing)

    Callee->>Session: handleAction(acceptCall)
    Session->>Sound: stopIncomingRingLoop
    Session->>Voice: createAndJoinCallGroup
    Voice->>Voice: 创建SimpleVoiceChat隐藏群组
    Session->>Caller: SyncPhoneCallStatePayload(active)
    Session->>Callee: SyncPhoneCallStatePayload(active)

    Note over Caller,Callee: 通话中...[tick监听超时]

    Caller->>Session: handleAction(endCall)
    Session->>Voice: leaveAndRemoveGroup
    Session->>Session: 记录通话历史
    Session->>Caller: SyncPhoneCallStatePayload(ended)
    Session->>Callee: SyncPhoneCallStatePayload(ended)

关键文件

文件说明
com/chenxi/chenxi_rfm/server/phone/PhoneCallSessionManager.java通话会话管理核心
com/chenxi/chenxi_rfm/server/phone/PhoneCallVoiceBridge.javaSimple Voice Chat 语音桥接
com/chenxi/chenxi_rfm/server/phone/PhoneServerSoundScheduler.java铃声调度器
com/chenxi/chenxi_rfm/server/phone/PhoneCallHistoryService.java通话记录服务
com/chenxi/chenxi_rfm/server/phone/PhoneCallNotifier.java通话状态推送
com/chenxi/chenxi_rfm/server/config/phone/PersistentPhoneRegistrySavedData.java手机注册表持久化
com/chenxi/chenxi_rfm/server/config/phone/PersistentPhoneCallHistorySavedData.java通话历史持久化
com/chenxi/chenxi_rfm/server/config/phone/PhoneCallRouteConfig.java号码转发路由表
com/chenxi/chenxi_rfm/server/voice/NfaVoicechatPlugin.javaSimpleVoiceChat 插件入口
com/chenxi/chenxi_rfm/server/voice/NfaVoicechatManager.javaVoicechatServerApi 持有器

关键流程

手机注册

  1. 玩家右键手机物品 → 打开 NFAPhoneMenu
  2. 客户端检查 NFA_PHONE_ID 组件 → 发送 RegisterPhoneAppPayload
  3. 服务端 registerPhone(phoneId, ownerUuid, ownerName)
    • phoneId 已存在且属于自己 → ALREADY_REGISTERED_BY_SELF
    • 已存在但属于他人 → ALREADY_REGISTERED_BY_OTHER
    • 不存在 → 生成新号码并创建记录

拨号流程

  1. 格式化目标号码(去除非数字,补全连字符)
  2. 从注册表查找被叫人
  3. 若号码不在注册表 → 尝试 PhoneCallRouteConfig.findForwardTarget(server, normalizedTarget) 号码转发
  4. 查重忙(isBusy)→ 主叫或被叫已在通话中则拒绝
  5. 创建 Session,状态 outgoing_ringing,开始响铃

语音桥接

  • 创建隐藏非持久化 Simple Voice Chat 群组
  • 将主叫和被叫加入同一群组
  • 挂断时解散群组
  • 群组名格式为 c + 时间戳后6位 base36 + 3位随机 base36(最长 10 字符)

重连支持

玩家重新登录时,onPlayerLoggedIn() 检查是否有活跃通话,有则重新推送当前状态包恢复通话 UI。

通话历史

每次通话结束写入两条记录:

  • 主叫方向:⬆ 呼叫 + "通话X秒" 或 "铃响X秒"
  • 被叫方向:⬇ 来电 + 同上

数据持久化

PersistentPhoneRegistrySavedData

文件:<world>/data/nfa_rfm/phone/registry.dat

List<Record: phoneId, ownerUuid, ownerName, phoneNumber>

PersistentPhoneCallHistorySavedData

文件:<world>/data/nfa_rfm/phone/call_history.dat

List<Record: ownerName, peerName, peerPhone, directionText, statusText, missed, timeMillis>

铃声参数

  • 音效:chenxi_rfm:phone_ring
  • 音量:25/16 ≈ 1.5625
  • 分类:SoundSource.RECORDS
  • 循环间隔:2 秒

注意事项

  1. 号码确定性:同一 UUID 永远生成同一号码,不可更改
  2. 多手机共享号码:一个玩家名下可注册多个手机,所有手机共享同一由 UUID 确定性生成的号码
  3. 语音依赖 Simple Voice Chat:若未安装该模组,语音桥接静默失败(通话仍可建立但无语音)
  4. 号码转发独立于注册:即使目标号码未注册,也可以通过路由表转发到注册号码
  5. tick 驱动一切:通话超时、铃声调度均依赖 ServerTick 事件

相关文档