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.
Declared imports (import_spec, place_import) rewrite a donor's console and
SD card ids to those two constants. See docs/content/docs/api/imports.mdx for
the shapes.
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= xdg_data_dir('azahar-emu')Azahar's data root, which is also the save root.
Not configurable, and deliberately: nothing on Azahar's command line names
this directory, so an override here would move only the half of the pair the
broker dumps and restores. The emulator would keep writing saves where XDG
puts them, and a session would restore into a tree nothing reads. launch
exports the root this resolved to instead, which is an agreement the two
cannot fall out of.
attributeCONFIG_DIR= xdg_config_dir('azahar-emu')Azahar's config directory, holding the qt-config.ini patched before each launch.
Not configurable, for the same reason as USER_DIR: the patch would land in
a file Azahar never opens, leaving it parked on its first-run setup.
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' * 32The 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' * 32The SD card id Azahar files saves under, fixed all-zeros like SYSTEM_ID.
attributeSDMC_DIR= USER_DIR / 'sdmc' / 'Nintendo 3DS' / SYSTEM_ID / SDCARD_IDThe emulated SD card's per-console directory.
attributeNAND_DATA_DIR= USER_DIR / 'nand' / 'data' / SYSTEM_IDThe 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.