不严谨的说 maimai 机台里跑着两套系统:
- amdaemon:一个原生后台服务,负责机台与世嘉服务器的全部通信(联网报到、读卡验证)
- Unity 游戏程序
整个过程我们可以分 6 步,双屏上的开机画面会同步显示每一步的进度状态
- 初始化中 CHECK
- 好 GOOD
- 坏 BAD
- 跳过 NA
1. 通电
机台通电后 Windows10 启动,amdaemon 自动运行,开机阶段做两件网络事:
- Allnet:向
NET 服务器发一次 initialize 请求,然后服务器返回游戏服务器地址、地区码、门店 ID - token:向
会员服务器的 get_data 接口拿一个 token 缓存起来,之后玩家扫码就用它验证身份
这两步完成后,amdaemon 置位 Core.IsReady,然后游戏程序开始初始化
游戏程序启动
Unity 场景加载,GameMainObject 执行初始化
- 加载原生 DLL 预加载库
- 读取机台 ini 配置
- 建 AmManager(投币、扫码、网络、双触摸屏等子系统的总管理器,此刻只建空壳)
- 建声音、数据、谱面管理器
- 生成 AES 密钥表
- 建局域网组件:Setting、Advertise、DeliveryChecker、Party
- 注册原生 daemon 异常回调
这一步不做任何网络请求,只建好整个程序的对象结构
2.5 等 amdaemon
每帧检查 Core.IsReady,没就绪就什么都不干,就绪后
- 调一次
GameMain.LateInitialize:把PowerOnProcess(开机自检进程)以 priority 50 放进进程调度器,并启动一个后台PingChecker线程 - 从这帧起,每帧固定执行:
Core.Execute→GameMain.Update(游戏主逻辑)→GameMain.LateUpdate
进程调度器机制:进程按优先级排队(数字越小越先跑),状态机为 Start→Update→Released,Released 的进程在晚更新阶段被释放并移除,开机链路完全靠这个调度器接力
AmManager
第 2 步只建了 AmManager 空壳,真正的子系统是在等 amdaemon 就绪后由 AmManager 自己创建的
GameMain.Update 每帧调 AmManager.Execute(),其内部状态机:
- WaitAmDaemonReady:等
Core.IsReady。就绪后一口气创建全部子系统——Backup、Credit(投币)、EMoney(国服没有)、Accounting、AimeReader(国服是扫码)、Network(网络测试)、Delivery(下发数据)、双触摸屏驱动NewTouchPanel[2]。全部建完后置IsReady=true,切到 Run - Run:每帧逐个执行这些子系统
也就是说:
Core.IsReady触发了两层:外层GameMainObject.Update启动开机自检进程,内层AmManager把硬件子系统真正建起来,两者独立同时运行
PingChecker
GameMain.LateInitialize 启动的异步后台线程,每小时测一轮服务器延迟:
- 触发时机:以 Allnet 下发的
Auth.AuthTime为基准,按它的分钟偏移推算整点起点,同小时只测一次(去重) - 一轮测 20 个 Ping 包:包间隔 >10 秒、单个超时 5 秒,失败的记丢包率
- 结果处理:去掉一个最大值和一个最小值后取平均作为延迟,连同丢包率 / 最大值写进 Backup(测试模式可查)
- 测试模式下自动中止,结果只用于网络诊断,不参与开机流程
3. 开机自检
开机画面出现,双屏开始逐项检查:
- 等 amdaemon:等
Core.IsReady。就绪后做一串硬件准备:初始化输入系统、读取 amdaemon 后的配置、初始化 OperationManager、探测 COM 串口(检查 USB4 集线器插在哪个口:COM20/24/28/32 之一,据此推断 LED 灯带接在哪个串口,比如探测到 COM20 就把灯映射到 COM21/COM23),初始化 LED 控制器,把 JVS 面板灯全部点亮成黑色 - 资源加载:等谱面 / 图片 / 模型资源全部装载完成(
assetManager.IsDone且谱面滑条线程空闲),屏幕显示加载进度。完成后再停留 2 秒 - 网络自检:逐项测试网络连通,屏幕逐行显示每项的 好坏。已知检查项共 8 项:IP 地址、网关、本地 DNS、跳数、线路类型、Net 认证、会员服务器、标题服务器。其中两项有硬超时:网络项 15 秒、Net 认证项 120 秒,超时判坏
- 会员服务器:若认证有效(
Auth.IsGood),向会员服务器发起存活检测。服务器可达显示好,否则坏,无效则跳过 - 标题服务器检查:让 OperationManager 下载游戏配置(GetGame*),只要成功下载过一次(
WasDownloadSuccessOnce)且服务器在线,就判好,完成后停留 2 秒
全部通过后进入 Released:把 StartupProcess 加进调度器,释放自己,并把 IsGameProcMode 置为 true(标记进入正式游戏流程)
4. 正式启动
这个进程做硬件 + 局域网的完整自检:
- 触摸屏:两块屏的驱动都就绪或报错为止,有错误把错误码记录进系统
- LED 灯带:两侧 LED 初始化完成,完成后初始化摄像头系统
- 摄像头:二维码摄像头 + 顶部摄像头就绪,完成后初始化读卡器,有摄像头错误码也记录进系统
- 数据加载:等数据管理器加载到 100%。完成后依次:配置收藏系统、初始化地图数据、下载谱面(DLMusicScore + DownloadMusicScore)
- 局域网-配置分发(WaitLinkDelivery):局域网内配置分发服务器就绪,若是服务端机且无局域网,直接 好 跳过。重复机号会显示”机台重复”错误
- 局域网-设置同步(WaitLinkSetting):同步事件模式、事件曲目数等设置。若局域网内出现重复机号,报错误 3201 并记录
- 局域网-Party(WaitLinkParty):加入 Party(
Party.Start( 机器组 ID)) - 局域网-LinkAdvertise:初始化 Advertise
- Ready:全部完成后停留 2 秒
- Released:把
WarningProcess加进调度器,释放自己,投币器切到正式游戏模式,重跑一次 GameManager 初始化;置IsInitializeEnd = true(这是游戏主循环开始做错误检测等逻辑的前置条件)
另外:进程启动时会挂一个 priority 51 的”通用消息进程”作为消息管理器(弹窗、计时器等通用 UI 都走它),并再次调用 OperationManager.Initialize()(这个调用是幂等的,重置到 检查认证 状态)
OperationManager
这台机台的一切标题服业务数据(游戏配置、事件、曲目、用户数据上传下载)都由 OperationManager 管 开机期间它跑一个四态状态机,标题画面出现前一般已走完:
- CheckAuth(检查认证):
Initialize()启动,轮询Core.IsReady && Auth.IsGood(amdaemon Allnet 认证)+ 门店 ID 非 0。认证通过才继续 - Download(下载配置):
_dataDownloader.Start()拉取全部GetGame*系列配置(GameSetting/GameEvent/GameRanking 等)。第 3 步标题服务器检查里的WasDownloadSuccessOnce就是这一步至少成功过一次 - Upload(上传数据):
_dataUploader.Start()把运营数据(投币记录等)上传 - Idle(空闲轮询):之后每帧检查配置是否有更新,需要时重新下载
标题画面出现后,OperationManager 就停在 Idle:每帧轮询配置更新、跑维护 / 关门计时器、
PingChecker每小时测速写 Backup
第 3、4 步全程不发起任何业务 API,只有配置下载(GetGame* 系)和 Ping 探测两类网络行为
5. 版权检查
进入版权画面之前先查 5 项,任一不满足就报错误 912 并走系统错误流程(最终退出游戏程序,见第 6 步):机器名含 “ACA”、显卡是 “GeForce GTX”、CPU 是 “Core(TM) i3-8100”、程序装在 X 盘、错误日志路径在 Y 盘
检查通过后显示版权警告画面。若地区码为 1(日服),播一段版权 logo 动画,播完结束;否则直接结束。整个进程生命周期内这个画面只显示一次(静态标记 OnceDisp)
结束时一次性启动两个常驻进程并释放自己:
- CommonProcess(priority 10):后台 UI 管理器:时间、音量、信息弹窗、计时器都是它
- AdvertiseProcess(priority 49):标题画面
错误码
屏幕报错画面会显示 4 位错误码(Error.Number 补零),开机链路内会出现的错误码全表:
| 码 | 名称 | 含义 | 触发时机 |
|---|---|---|---|
| 0912 | GraphicBoard_RenderError | 显卡 / 图形板错误 | 第 5 步户口校验任一失败;或开发机渲染宽度不足 |
| 3100 | CameraNotFill | 摄像头画面缺失 | 摄像头自检(第 4 步)两摄像头未能全部出画面 |
| 3101 | CodeReader_InitializeFailed | 扫码器初始化失败 | 二维码摄像头不可用 |
| 3102 | PhotoCamera_NotFound | 拍照摄像头没找到 | 拍照摄像头不可用 |
| 3201 | GroupRole_DuplicateParent | 局域网内重复机号 | 第 4 步设置同步 / 广告分发发现重复机号 |
| 3300-3303 | TouchPanel_Left/Right_OpenError/InitError | 触摸屏打开 / 初始化失败 | 第 4 步触摸屏自检 |
| 6501 | AimeConnectError | AIME 读卡连接错误 | 原生读卡器(开机不显示,运行中刷卡时报) |
| 6506 | AimeFiruUpdateError | AIME 固件更新错误 | 原生读卡器(运行中) |
其余错误码(LED 串口板 0-9、局域网 Party 组网、网络记账 E00-E15 等)属于底层诊断,不在错误屏显示,测试模式里可查
开机中一直 初始化 意味着什么
- 一直 初始化(闪烁):还在等待该步骤完成。常见于等 amdaemon、等资源加载、等网络自检、等会员服务器检测、等标题服下载
- 坏:该项失败。多数自检项 坏 后会继续往下走,部分会直接系统错误然后退出,比如 912
- 硬超时:网络项 15 秒、Net 认证项 120 秒后强制判 Bad。会员服务器检测与标题服下载则一直等到有结论为止(依赖请求自身的超时配置)
- 长期卡在 初始化:说明该项依赖的服务器 / 硬件无响应,通常过不了它后续依赖的步骤(例如 Net 认证超时后,标题服务器检查也过不了)
6. 初始化完毕
AdvertiseProcess 负责标题待机:显示 logo → 标题 → 判断榜单:
- 检测到输入 → 淡出过渡到
EntryProcess(游戏入口),此后投币 / 刷码 → 确认 → 进入游戏 - 有 demo → 进
AdvDemoProcess(放 autoplay 的 pv),否则重新回到标题画面
机台进入标题待机的那一刻,就是”初始化完毕”:可投币、可读卡、服务器在线、配置已下载。此后 OperationManager 停在 Idle 态(第 4 步详解),每帧检查配置更新、跑维护 / 关门计时器,PingChecker 每小时发一次测速包更新延迟数据
两个后台服务
从第 2.5 步起,GameMain.Update 每帧还检查两件事:
- 错误检测:若已初始化完成且系统有错误(且配置允许),强制登出玩家、终止 Party、把
ErrorProcess加进调度器、置错误模式、关声音关投币 - TEST 按钮:按到测试键(且处于游戏或错误模式),强制登出玩家、把
TestModeProcess加进调度器、记录”进入测试模式”、进入测试子流程
什么时候退出 / 重启
GameMainObject.Update 每帧还看四个退出标志,任一命中就结束游戏程序:
- 系统异常 → 直接退出
IsGotoSystemTest(进系统测试)→Core.Kill(3)后退出IsGotoReboot(需要重启)→ 需要自动重启则Core.Reboot(),否则Core.Kill(1)后退出IsGotoSystemError(系统错误,如第 5 步的 912)→Core.Kill(2)后退出
结
以上就是舞萌 DX 机台开机初始化的整个软件底层行为,如果您对此感兴趣,欢迎 follow 本 blog,将本站添加到收藏夹 / 订阅 rss,后续会更新更多此类文章
