webstation-broker
DeveloperPython referenceemulators

emulators.azahar

Azahar (Nintendo 3DS) launcher: qt-config.ini patching and SIGTERM shutdown.

Azahar (Nintendo 3DS) launcher: qt-config.ini patching and SIGTERM shutdown.

Azahar has no control API reachable from outside the process. Its only network surface is a UDP RPC server that reads and writes emulated memory, with nothing for state or shutdown, and its command line takes a ROM path and little else. So there is no mid-session save state here: persistence is the game's own save data, written to host files under the emulated SD card and NAND. Azahar installs no SIGTERM handler, so the stop is a hard kill and the dump takes whatever the game had already committed to disk.

The 3DS data root is XDG-derived ($XDG_DATA_HOME/azahar-emu), with config alongside it under $XDG_CONFIG_HOME. Azahar also has a portable mode that triggers on a user/ directory in the working directory, which is why the launch never chdir's anywhere it might find one.

Save data paths are stable across containers: the console and SD card ids Azahar files saves under are hardcoded to all-zeros rather than generated per install, so a save dumped in one session restores into the next.

attributelog
= logging.getLogger(__name__)
attributeROM_ROOT
= Path(os.environ.get('ROM_ROOT', '/romm'))

Library root a resolved ROM must live under (env ROM_ROOT, default /romm).

attributeUSER_DIR
= Path(os.environ.get('AZAHAR_USER_DIR', _xdg_dir('XDG_DATA_HOME', '.local/share')))

Azahar's data root, the save root (env AZAHAR_USER_DIR, default $XDG_DATA_HOME/azahar-emu).

attributeCONFIG_DIR
= Path(os.environ.get('AZAHAR_CONFIG_DIR', _xdg_dir('XDG_CONFIG_HOME', '.config')))

Azahar's config directory (env AZAHAR_CONFIG_DIR, default $XDG_CONFIG_HOME/azahar-emu).

attributeCONFIG_PATH
= CONFIG_DIR / 'qt-config.ini'

The qt-config.ini patched before every launch.

attributeAZAHAR_LOG_PATH
= Path(os.environ.get('AZAHAR_LOG_PATH', '/config/azahar.log'))

The emulator log file (env AZAHAR_LOG_PATH, default /config/azahar.log).

attributeSYSTEM_ID
= '0' * 32

The console id Azahar files saves under.

Fixed all-zeros rather than generated per install, so these paths are the same in every container and a dumped save restores where the next session looks.

attributeSDCARD_ID
= '0' * 32

The SD card id Azahar files saves under, fixed all-zeros like SYSTEM_ID.

attributeSDMC_DIR
= USER_DIR / 'sdmc' / 'Nintendo 3DS' / SYSTEM_ID / SDCARD_ID

The emulated SD card's per-console directory.

attributeNAND_DATA_DIR
= USER_DIR / 'nand' / 'data' / SYSTEM_ID

The emulated NAND's per-console data directory.

attributeROM_EXTENSIONS
= ('.3ds', '.cci', '.zcci', '.cxi', '.zcxi', '.app', '.3dsx', '.z3dsx', '.elf', '.axf', '.bin')

Formats Azahar boots directly, best first; a folder holding several candidates picks by this order.

No .cia: that is an installable package rather than something the emulator boots.