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_EXTENSIONSBootable disc formats, .iso only.
attributelog_path= XEMU_LOG_PATHThe 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_DIRNAMEHost-side directory the dump and restore read and write.
attributesave_root= self.hdd_image.parentThe 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= Falseattribute_title_idOptional[str]= NoneFunctions
func__init__(self) -> NoneResolve 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.
paramselfReturns
Nonefunc_clear_staging(self) -> NoneRemove the staging directory and everything under it, logging a failure.
paramselfReturns
Nonefunc_inject_saves(self) -> intPre-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.
paramselfReturns
intThe number of files that landed on the image.
func_extract_saves(self) -> intPost-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.
paramselfReturns
intThe number of files staged.
funcresolve_rom_file(self, path) -> Optional[Path]The disc image to boot for path.
paramselfparampathPathA ROM file, or a folder searched up to two levels deep.
Returns
typing.OptionalThe file itself, the best-ranked .iso in the folder, or None.
funcprepare_restore(self) -> NoneGet 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.
paramselfReturns
Nonefunclaunch(self, rom_path, resume_slot) -> NoneInject any restored saves, pin display settings and boot the disc.
paramselfparamrom_pathPathThe XISO to boot.
paramresume_slotOptional[int]Ignored with a warning; a raw image holds no states.
Returns
Nonefuncsave_and_exit(self, slot) -> dict[str, Any]Stop xemu and stage the launched title's saves for the dump.
paramselfparamslotOptional[int]Ignored; there are no save states.
Returns
dictThe state fields all None (state_saved, state_slot,