webstation-broker
DeveloperPython referenceemulatorsemulators.xemu

emulators.xemu.Xemu

Original Xbox via xemu, with saves synced at the FATX level.

Original Xbox via xemu, with saves synced at the FATX level.

xemu is a QEMU derivative with no control channel the broker can reach, so the session is command line in (-dvd_path) and SIGTERM out. SIGTERM gives QEMU a clean shutdown that flushes the HDD image the post-close extraction then reads, so the grace window is long enough for the flush to land before the SIGKILL escalation tears it. Any xemu the broker does not own is reaped with SIGKILL before every hook, because an orphan keeps writing the image the hooks are about to touch. Display settings (renderer and fullscreen) are pinned into xemu.toml before each launch, since xemu rewrites that file on exit and drops both.

Save data lives inside the raw HDD image's FATX E partition. An archive the activate restored lands in a staging directory next to the image and is injected into E:/UDATA and E:/TDATA before boot; after exit the launched title's trees are extracted back into the staging directory for the standard dump. There are no save states: the image is kept raw so pyfatx can read it, and a raw image cannot hold QEMU internal snapshots, so supports_states stays off and a resume slot is logged and ignored.

Attributes

attributename
= 'xemu'

Provider key, xemu.

attributedisplay_name
= 'xemu'

Human-readable name.

attributerom_extensions
= ROM_EXTENSIONS

Bootable disc formats, .iso only.

attributelog_path
= XEMU_LOG_PATH

The emulator log file.

attributeterm_timeout
= float(os.environ.get('XEMU_STOP_WAIT', '15'))

SIGTERM grace before SIGKILL (env XEMU_STOP_WAIT, default 15).

attributehdd_image
= _hdd_image_path()

The HDD image xemu mounts, resolved once per session.

attributestaging_dir
= self.hdd_image.parent / SAVE_STAGING_DIRNAME

Host-side directory the dump and restore read and write.

attributesave_root
= self.hdd_image.parent

The image's parent directory, which the save subtrees hang off.

attributesave_subtrees
= (SAVE_STAGING_DIRNAME,)

The staging directory name, scoping dump and restore to it.

attribute_restore_pending
= False
attribute_title_idOptional[str]
= None

Functions

func__init__(self) -> None

Resolve the HDD image and staging directory for this session.

An image parked under .<name>.prev by a previous broker version is moved back into place when the configured image is missing.

paramself

Returns

None
func_clear_staging(self) -> None

Remove the staging directory and everything under it, logging a failure.

paramself

Returns

None
func_inject_saves(self) -> int

Pre-launch hook: write every staged file into the FATX E partition.

Hidden entries and symlinks in the staging dir are skipped. Directory components are matched case-insensitively against the disk so an archive whose case differs lands in the existing directory.

paramself

Returns

int

The number of files that landed on the image.

func_extract_saves(self) -> int

Post-close hook: copy the title's save data out of the FATX E partition.

Files land in the (already cleared) staging dir carrying fresh mtimes, so the dump's launch-baseline filter ships them all: the archive is the title's complete save set, not a delta. Without a title id every title's UDATA and TDATA is extracted.

paramself

Returns

int

The number of files staged.

funcresolve_rom_file(self, path) -> Optional[Path]

The disc image to boot for path.

paramself
parampathPath

A ROM file, or a folder searched up to two levels deep.

Returns

typing.Optional

The file itself, the best-ranked .iso in the folder, or None.

funcprepare_restore(self) -> None

Get the image and staging dir ready before the archive is extracted.

Stops anything holding the image, makes sure it is raw, and empties the staging dir: leftovers from the previous session's dump would otherwise mix into the injection, and the newer-file guard could skip archive members over them. Marks the restore pending so the next launch injects what lands.

paramself

Returns

None
funclaunch(self, rom_path, resume_slot) -> None

Inject any restored saves, pin display settings and boot the disc.

paramself
paramrom_pathPath

The XISO to boot.

paramresume_slotOptional[int]

Ignored with a warning; a raw image holds no states.

Returns

None
funcsave_and_exit(self, slot) -> dict[str, Any]

Stop xemu and stage the launched title's saves for the dump.

paramself
paramslotOptional[int]

Ignored; there are no save states.

Returns

dict

The state fields all None (state_saved, state_slot,

On this page