REPORT
CEPATO Technical Note2026.08.05

A Detailed Look at the maimai Cabinet's Boot Initialization Process

This article details the series of initialization behaviors during a maimai cabinet's boot, and provides an error code reference

Chongxi
Author:Chongxi
steam: —·spotify: —
Tags:#maimai#Software Talk#Networking
ANALYSIS

Loosely speaking, two systems run on a maimai cabinet:

  • amdaemon: a native background service responsible for all communication between the cabinet and SEGA’s servers (network check-in, card verification)
  • The Unity game program

We can break the whole process into 6 steps; the boot screen on the dual displays shows each step’s progress status in sync

  • 初始化中 CHECK

  • 好 GOOD

  • 坏 BAD

  • 跳过 NA

1. Power on#

After the cabinet powers on, Windows 10 boots and amdaemon starts automatically. During the boot phase it does two network things:

  • Allnet: sends one initialize request to the NET服务器, and the server returns the game server address, region code and store ID
  • AIME registration: locally initializes the code-scanning card reader (Chime.Instance.Init, registering the keychip identity). At boot it doesn’t send get_data and doesn’t fetch a token; get_data is only initiated by amdaemon when a player scans, and the token comes back with the scan response

After these two steps complete, amdaemon sets Core.IsReady, and then the game program begins initializing

Game program startup#

The Unity scene loads and GameMainObject performs initialization

  • Loads the native DLL preload libraries
  • Reads the cabinet’s ini config
  • Creates AmManager (the overall manager for subsystems like coin insertion, code scanning, network and dual touchscreens; for now only an empty shell)
  • Creates the sound, data and chart managers
  • Generates the AES key table
  • Creates LAN components: Setting, Advertise, DeliveryChecker, Party
  • Registers the native daemon exception callback

This step makes no network requests at all; it only builds the whole program’s object structure

2.5 Waiting for amdaemon#

Every frame it checks Core.IsReady; if not ready it does nothing. Once ready:

  • Calls GameMain.LateInitialize once: puts PowerOnProcess (the boot self-check process) into the process scheduler at priority 50, and starts a background PingChecker thread
  • From this frame on, every frame runs: Core.Execute → GameMain.Update (main game logic) → GameMain.LateUpdate

Process scheduler mechanism: processes queue by priority (smaller numbers run first), the state machine is Start→Update→Released, and Released processes are freed and removed during the late update phase. The entire boot chain is relayed through this scheduler

AmManager#

Step 2 only built an empty AmManager shell; the real subsystems are created by AmManager itself after waiting for amdaemon to be ready

GameMain.Update calls AmManager.Execute() every frame, and its internal state machine is:

  1. WaitAmDaemonReady: waits for Core.IsReady. Once ready it creates all subsystems: Backup, Credit (coin insertion), EMoney (the Chinese server doesn’t have it), Accounting, AimeReader (code scanning on the Chinese server), Network (network test), Delivery (pushed data), and the dual touchscreen driver NewTouchPanel[2]. After everything is built it sets IsReady=true and switches to Run
  2. Run: executes these subsystems one by one every frame

In other words, Core.IsReady triggers two layers: the outer GameMainObject.Update starts the boot self-check process, and the inner AmManager actually builds the hardware subsystems; the two run independently at the same time

PingChecker#

An asynchronous background thread started by GameMain.LateInitialize; it measures server latency once an hour:

  • Trigger timing: based on Auth.AuthTime delivered by Allnet, it derives the top-of-hour start from its minute offset, and only measures once per hour (deduplicated)
  • 20 ping packets per round: packet interval > 10 seconds, individual timeout 5 seconds; failures are counted toward the packet loss rate
  • Result handling: drop the highest and lowest values and average the rest as the latency, then write it into Backup along with the packet loss rate and maximum (viewable in test mode)
  • Automatically aborted in test mode; the results are only used for network diagnostics and don’t take part in the boot flow

3. Boot self-check#

The boot screen appears and the dual displays begin checking item by item:

  1. Wait for amdaemon: waits for Core.IsReady. Once ready, a string of hardware preparation: initializes the input system, reads the config after amdaemon, initializes OperationManager, probes the COM serial ports (checks which port the USB4 hub is plugged into — one of COM20/24/28/32 — and from that infers which serial port the LED strips are on; if COM20 is detected, for example, the lights are mapped to COM21/COM23), initializes the LED controller, and lights all JVS panel lights as black
  2. Asset loading: waits for all chart/image/model assets to finish loading (assetManager.IsDone and the chart slider thread idle), with loading progress shown on screen. After completion it lingers for another 2 seconds
  3. Network self-check: tests network connectivity item by item, with the screen showing each item’s 好 or 坏 line by line. There are 8 known check items: IP address, gateway, local DNS, hop count, line type, Net authentication, membership server, title server. Two of them have hard timeouts: the network item at 15 seconds and the Net authentication item at 120 seconds; on timeout it’s judged 坏
  4. Membership server: if authentication is valid (Auth.IsGood), sends a liveness check to the membership server. If the server is reachable it shows 好, otherwise 坏; if invalid, it’s skipped
  5. Title server check: has OperationManager download the game config (GetGame*). As long as it has downloaded successfully at least once (WasDownloadSuccessOnce) and the server is online, it’s judged 好. After completion it lingers 2 seconds

Once everything passes it enters Released: adds StartupProcess to the scheduler, frees itself, and sets IsGameProcMode to true (marking entry into the formal game flow)

4. Formal startup#

This process performs a complete hardware + LAN self-check:

  1. Touchscreens: until both screens’ drivers are ready or error out; errors record their error codes into the system
  2. LED strips: both sides’ LEDs finish initializing, after which the camera system is initialized
  3. Cameras: the QR code camera + top camera become ready, after which the card reader is initialized; camera error codes are also recorded into the system
  4. Data loading: waits for the data manager to reach 100%. After that, in order: configure the favorites system, initialize map data, download charts (DLMusicScore + DownloadMusicScore)
  5. LAN — config delivery (WaitLinkDelivery): the LAN’s config delivery server is ready; if this is the server machine and there’s no LAN, it’s directly judged 好 and skipped. Duplicate machine numbers display a “机台重复” error
  6. LAN — setting sync (WaitLinkSetting): syncs settings such as event mode and event track count. If a duplicate machine number appears in the LAN, it reports error 3201 and records it
  7. LAN — Party (WaitLinkParty): joins the Party (Party.Start(机器组ID))
  8. LAN — LinkAdvertise: initializes Advertise
  9. Ready: after everything completes it lingers for 2 seconds
  10. Released: adds WarningProcess to the scheduler, frees itself, switches the coin mechanism to formal game mode, and reruns GameManager initialization once; sets IsInitializeEnd = true (this is the precondition for the main game loop to begin doing logic such as error detection)

Also: when the process starts it attaches a “general message process” at priority 51 as the message manager (popups, timers and other general UI all go through it), and calls OperationManager.Initialize() again (this call is idempotent, resetting to the 检查认证 state)

OperationManager#

All of the cabinet’s title-server business data (game config, events, tracks, user data upload/download) is managed by OperationManager During boot it runs a four-state state machine, which is usually finished before the title screen appears:

  1. CheckAuth (check authentication): started by Initialize(), polls Core.IsReady && Auth.IsGood (amdaemon Allnet authentication) + store ID non-zero. Only continues once authentication passes
  2. Download (download config): _dataDownloader.Start() pulls all the GetGame* configs (GameSetting/GameEvent/GameRanking etc.). The WasDownloadSuccessOnce in step 3’s title server check means this step succeeded at least once
  3. Upload (upload data): _dataUploader.Start() uploads operational data (coin insertion records etc.)
  4. Idle (idle polling): afterwards it checks every frame whether the config has updates and re-downloads when needed

After the title screen appears, OperationManager stays in Idle: polling for config updates every frame, running maintenance/closing timers, and PingChecker measuring speed and writing to Backup every hour

Steps 3 and 4 never send any business API calls at all; the only network activity is config downloading (the GetGame* family) and ping probes

Before entering the copyright screen it checks 5 items; if any one is not satisfied, it reports error 912 and goes through the system error flow (ultimately exiting the game program, see step 6): the machine name contains “ACA”, the GPU is “GeForce GTX”, the CPU is “Core(TM) i3-8100”, the program is installed on drive X, and the error log path is on drive Y

After the checks pass, the copyright warning screen is shown. If the region code is 1 (Japanese server), a copyright logo animation plays and then ends; otherwise it ends directly. This screen is displayed only once over the process’s entire lifetime (the static flag OnceDisp)

On finishing, it starts two resident processes at once and frees itself:

  • CommonProcess (priority 10): the background UI manager — time, volume, info popups and timers all belong to it
  • AdvertiseProcess (priority 49): the title screen

Error codes#

The error screen displays a 4-digit error code (Error.Number zero-padded); here’s the full table of error codes that can appear in the boot chain:

CodeNameMeaningTrigger
0912GraphicBoard_RenderErrorGPU/graphics board errorAny of step 5’s checks fails; or the dev machine’s render width is insufficient
3100CameraNotFillCamera feed missingCamera self-check (step 4): the two cameras fail to both produce a picture
3101CodeReader_InitializeFailedCode reader initialization failedQR code camera unavailable
3102PhotoCamera_NotFoundPhoto camera not foundPhoto camera unavailable
3201GroupRole_DuplicateParentDuplicate machine number in the LANStep 4 setting sync/ad delivery finds a duplicate machine number
3300-3303TouchPanel_Left/Right_OpenError/InitErrorTouchscreen open/init failedStep 4 touchscreen self-check
6501AimeConnectErrorAIME card reader connection errorNative card reader (not shown at boot; reported when swiping during gameplay)
6506AimeFiruUpdateErrorAIME firmware update errorNative card reader (during gameplay)

The remaining error codes (LED serial board 0-9, LAN Party networking, network accounting E00-E15, etc.) belong to low-level diagnostics, aren’t shown on the error screen, and can be checked in test mode

What it means when the screen stays on 初始化 throughout boot#

  • Always 初始化 (blinking): still waiting for that step to complete. Commonly seen while waiting for amdaemon, asset loading, network self-check, membership server detection, or title server download
  • 坏: that item failed. Most self-check items continue on after 坏, while some go straight to a system error and exit, such as 912
  • Hard timeouts: the network item is forced to Bad after 15 seconds and the Net authentication item after 120 seconds. Membership server detection and title server download wait until there’s a conclusion (depending on each request’s own timeout config)
  • Stuck on 初始化 for a long time: means the server/hardware that item depends on isn’t responding, and it usually can’t get past the steps that depend on it (for example, after Net authentication times out, the title server check can’t pass either)

6. Initialization complete#

AdvertiseProcess handles title standby: shows the logo → title → decides on the ranking:

  • Input detected → fades out and transitions to EntryProcess (game entry), after which inserting coins/swiping → confirm → enter the game
  • Demo available → enter AdvDemoProcess (plays the autoplay PV); otherwise return to the title screen

The moment the cabinet enters title standby is “initialization complete”: you can insert coins, read cards, the server is online and the config has been downloaded. After that OperationManager stays in Idle (detailed in step 4), checking for config updates every frame, running maintenance/closing timers, and PingChecker sending a speed-test packet every hour to update the latency data

The two background services#

From step 2.5 onward, GameMain.Update also checks two things every frame:

  • Error detection: if initialization is complete and the system has an error (and the config permits), forcibly logs out the player, terminates the Party, adds ErrorProcess to the scheduler, sets error mode, and mutes the sound and disables coin insertion
  • TEST button: if the test key is pressed (and the machine is in game or error mode), forcibly logs out the player, adds TestModeProcess to the scheduler, logs “entering test mode”, and enters the test sub-flow

When it exits or restarts#

GameMainObject.Update also watches four exit flags every frame; hitting any one ends the game program:

  • System exception → exit directly
  • IsGotoSystemTest (enter system test) → Core.Kill(3) then exit
  • IsGotoReboot (needs restart) → Core.Reboot() if auto-restart is needed, otherwise Core.Kill(1) then exit
  • IsGotoSystemError (system error, such as 912 in step 5) → Core.Kill(2) then exit

Conclusion#

That’s the whole low-level software behavior of a 舞萌 DX cabinet’s boot initialization. If you find this interesting, feel free to follow this blog, add the site to your bookmarks or subscribe to the RSS feed; more articles like this will be coming

Chongxi
CHONGXIAuthor
Steam—
Spotify—
Published at:2026.08.05
maimai
Series_Associated

PROJECT: MAIMAI

This article is included in a featured series. Visit the project page to explore the full collection.

Classified
Distribution Notice

A Detailed Look at the maimai Cabinet's Boot Initialization Process

Author CHONGXI/2026.08.05/CEPATO-2026-0805-MAIMAI

This work is licensed under CC BY-NC-SA 4.0. Redistribution, remixing and adaptation are allowed for non-commercial use, provided the same license is used and the original author is credited.

SubscribeDonate
Discussion
Archive_Ref
Copyright © 2011–2026 Chongxi & CEPATO
Powered by Astro & CEPATO-NEXT
StatusNon-Collaborative_Entity // CEPATO_NEXT_v27.0

Type a keyword to search