emulators.retroarch.Retroarch
RetroArch driven over its stdin command interface.
RetroArch driven over its stdin command interface.
One launcher for every platform in PLATFORMS: platform is set from the
activate payload before launch, and picks the core, the ROM extensions and
the save scope. Saves, loads and quit go over stdin; replies come back on a
stdout pipe drained by a reader thread, and saves are confirmed on disk.
Attributes
attributename= 'retroarch'Registry key, retroarch.
attributedisplay_name= 'RetroArch'Shown as "RetroArch".
attributesave_root= RA_DATA_DIRRA_DATA_DIR, the broker-managed data root.
attributelog_path= RA_LOG_PATHRA_LOG_PATH, where RetroArch's stderr goes.
attributesupports_states= TrueOn; save states work for every core unless its
platform entry opts out of savestate.
attributesupports_disc_swap= TrueOn; discs are swapped through the virtual tray.
attributestate_slot= STATE_SLOTSTATE_SLOT, the one slot the broker works in.
attributestate_dir= STATE_DIRSTATE_DIR, the broker-managed savestate directory.
attributeterm_timeout= float(os.environ.get('RETROARCH_STOP_WAIT', '15'))Seconds QUIT gets before SIGTERM, from
RETROARCH_STOP_WAIT (default 15).
attributeplatformOptional[str]= NoneThe RomM platform slug, set before launch.
attribute_rom_basestr= ''The loaded content's basename, which RetroArch names its state and SRAM files after.
attribute_slot_homed= FalseWhether the current slot has been parked on STATE_SLOT since launch.
attribute_launch_seq= 0Launch generation, bumped on every launch and stop so stale background waits bail out.
attribute_stdout_buf= bytearray()Replies read off RetroArch's stdout and not yet consumed.
attribute_stdout_lock= threading.Lock()Guards _stdout_buf between the reader thread and the callers waiting on replies.
attribute_readerOptional[threading.Thread]= NoneThe thread draining RetroArch's stdout into _stdout_buf.
attribute_playlistOptional[Path]= NoneThe playlist this session booted, or None when the content was not an .m3u.
attribute_disc_indexint= 0Where the tray currently sits.
RetroArch has no way to read the mounted disc back, so the broker remembers what it did and steps relative to that.
attribute_disc_lock= threading.Lock()Serializes swap_disc against itself and against the deferred resume load.
Both poll for PLAYING and then act on the live process, and a
LOAD_STATE landing inside a tray-settle window is the collision.
attributesave_subtreestuple[str, ...]Per-platform dump scope.
Cores whose savefile dir is also their app-data dir (dolphin) narrow the archive to real save files.
attributerom_extensionstuple[str, ...]The loaded platform's ROM extensions, or none when no platform is mapped.
Functions
func__init__(self) -> NoneSet up the reply buffer, reader thread slot and tray tracking for a session.
paramselfReturns
Nonefuncresolve_rom_file(self, path) -> Optional[Path]File the core should boot for path.
A file is taken as is. A folder is searched one level deep and ranked by
_pick_rom_file against the platform's extensions.
paramselfparampathPathThe ROM as RomM delivered it, a file or a folder.
Returns
typing.OptionalThe file to boot, or None when the platform is unmapped, the path
func_spawn_ra(self, cmd, env) -> NoneSpawn with a real stdout pipe (stderr to the log).
stdout carries the command replies, so it must stay clean. A reader
thread drains it into _stdout_buf. Unlike the shared _spawn, this
does not record the pid.
paramselfparamcmdlist[str]The argv to run.
paramenvdict[str, str]The environment to run it in.
Returns
Nonefunc_read_stdout(self) -> NoneReader thread body: copy RetroArch's stdout into _stdout_buf until it closes.
paramselfReturns
Nonefunc_wait_for_reply(self, prefixes, timeout) -> Optional[str]Wait for a stdout reply matching one of prefixes; consume it and return it.
Replies are newline-terminated except the bare echoes of the *_SLOT
commands and GET_STATUS CONTENTLESS, so a match with no newline after
it is taken as the whole rest of the buffer.
paramselfparamprefixesUnion[str, tuple[str, ...]]One prefix, or several of which the earliest match wins.
paramtimeoutfloatSeconds to keep polling the buffer.
Returns
typing.OptionalThe matched line, with everything up to it dropped from the buffer,
func_send(self, cmd, wait_prefix=None, timeout=5.0) -> Optional[str]Write one command to RetroArch's stdin, optionally waiting for its reply.
paramselfparamcmdstrThe command line to send; the newline is added here.
paramwait_prefixOptional[Union[str, tuple[str, ...]]]= NoneReply prefix(es) to wait for, or None for a command with no reply.
paramtimeoutfloat= 5.0Seconds to wait for the reply.
Returns
typing.OptionalThe reply line when one was waited for and arrived, otherwise None,
funclaunch(self, rom_path, resume_slot) -> NoneStart RetroArch on rom_path with the platform's core.
Any running session is stopped first. The core is downloaded if missing, its assets linked, and the broker config written; then RetroArch starts fullscreen with that config appended. A resume is deferred to a background thread that waits for the game to be up.
Raises
RuntimeError: Whenplatformhas no core mapped, or the RetroArch binary (RETROARCH_BIN) is not onPATH.
paramselfparamrom_pathPathThe file to boot, as returned by resolve_rom_file.
paramresume_slotOptional[int]The slot to load once the game is running, or None.
Returns
Nonefunc_deferred_load_state(self, slot, seq) -> NoneLoad slot once RetroArch reports the content PLAYING.
Cores with no game running yet (Dolphin boot screen) reject loads, so
this polls GET_STATUS first, then waits out RESUME_LOAD_SETTLE and
for the slot to hold a state file before loading.
paramselfparamslotintThe slot to load.
paramseqintThe launch generation this load belongs to; a relaunch or stop
bumps _launch_seq and ends the wait.
Returns
Nonefunc_wait_until_playing(self, deadline, seq) -> boolBlock until the core reports a running game, or deadline passes.
A tray command sent before the content is up is dropped, and there is
no error to catch when it is. seq is the launch generation this
wait belongs to, checked the same way _deferred_load_state checks
_launch_seq, so a relaunch during the wait ends it rather than
letting a stale wait later act on the new session.
paramselfparamdeadlinefloatA time.monotonic() value to give up at.
paramseqintThe launch generation this wait belongs to.
Returns
boolTrue once GET_STATUS reports PLAYING; False on timeout, relaunch
funcswap_disc(self, path) -> boolMount the playlist entry at path without restarting the core.
Stepping is relative and wraps, because the command protocol has
DISK_NEXT but no way to set an index or read the current one back.
The tray is opened, stepped the needed number of times, and closed;
the tracked index only moves once the session is confirmed to have
outlived the sequence.
paramselfparampathPathThe disc image to mount; it must be listed in the session's playlist.
Returns
boolTrue once the new disc is in the tray (or was already mounted);
func_home_state_slot(self) -> NonePark RetroArch's current state slot on STATE_SLOT.
Absolute, not relative: MINUS runs the slot down onto its -1 floor first, so this holds no matter where the slot was.
paramselfReturns
Nonefunc_try_save(self) -> boolSend SAVE_STATE once and confirm the file landed in STATE_SLOT.
paramselfReturns
boolTrue when the slot's file changed on disk within
funcsave_state(self, slot) -> boolSave the running game into STATE_SLOT.
slot is what RomM asked for and is ignored: this saves into
STATE_SLOT and the caller reads the effective slot back off
state_slot.
Homing costs a couple of seconds, so it runs once per launch and then only to recover: a save landing on another slot means the player moved it with their own hotkeys, and re-homing puts the next one back.
paramselfparamslotintThe slot RomM asked for; ignored.
Returns
boolTrue once the state file is confirmed on disk; False when the core
funcload_state(self, slot) -> boolLoad STATE_SLOT into the running game.
LOAD_STATE_SLOT is absolute and does not move the current slot, so
this needs no homing. The echo carries no success bit and a load writes
nothing to disk, so an empty slot is ruled out here instead.
paramselfparamslotintThe slot RomM asked for; ignored in favour of STATE_SLOT.
Returns
boolTrue once RetroArch echoes the command; False when the core is not
funcstate_path(self) -> Optional[Path]The newest state file for the loaded content in STATE_SLOT, or None.
paramselfReturns
typing.OptionalThe file found by _newest_state, or None before a launch has set
funcstate_screenshot_path(self) -> Optional[Path]The thumbnail RetroArch wrote beside the working slot's state, or None.
RetroArch writes the thumbnail as <state file>.png beside the state,
so it is only meaningful next to the state it was taken with.
paramselfReturns
typing.OptionalThe .png next to state_path, or None when either is missing.
funcstate_target(self, filename) -> Optional[Path]Where a pushed state called filename belongs.
RetroArch looks a state up by the name it derives from the loaded content, so the target is that name in this broker's slot and a pushed one only has to say which content it belongs to.
paramselfparamfilenamestrThe name the pushed state was stored under.
Returns
typing.OptionalThe existing slot file when there is one, else the slot's path at
funcsave_and_exit(self, slot) -> dict[str, Any]Save state when asked, flush SRAM, and quit RetroArch.
The state save is skipped when slot is None or the platform entry
opts out of savestate. SAVE_FILES is always sent so the save dump
ships current save data, then the process is quit through _quit.
paramselfparamslotOptional[int]The slot to save into, or None to exit without writing a state.
Returns
dictA dict with {"state_saved", "state_slot", "state_file"}: whether
func_quit(self) -> NoneQuit RetroArch gracefully over stdin, escalating to stop if it stays up.
QUIT is sent, then sent again after QUIT_CONFIRM_GAP if the process
is still running, and given QUIT_WAIT to exit. A graceful exit
forgets the handle; anything else falls through to the base stop and
its SIGTERM.
paramselfReturns
Nonefuncstop(self) -> NoneStop RetroArch, invalidating any in-flight deferred state load before the kill.
paramselfReturns
None