emulators.xenia.Xenia
Emulator adapter for Xenia Edge (Xbox 360).
Emulator adapter for Xenia Edge (Xbox 360).
Activate drops the previous session's saved games out of the content tree and hands the restore an unconditional overwrite of the profile package, which the clear has to leave standing. Launch resolves a bootable file out of a library entry and records a session baseline. Exit stops the process and refreshes the mtime of every file under the content title directories written this session, so the delta dump ships those titles whole while other titles' content stays filtered out. There are no save states, so a resume slot is logged and ignored.
Attributes
attributename= 'xenia'Provider key, xenia.
attributerom_cacheable= TrueOn; with the ROM cache enabled, launch boots a local copy of the ROM.
attributedisplay_name= 'Xenia'Human-readable name.
attributesave_root= DATA_DIRThe storage root the save subtrees hang off.
attributesave_subtrees= (CONTENT_SUBTREE,)content, the save and profile tree.
attributerom_extensions= ROM_EXTENSIONSBootable formats, best first.
attributelog_path= XENIA_LOG_PATHThe emulator log file.
attributeclears_stale_saves= TrueOn; activate empties every title's saved-game tree.
attribute_session_start= float('inf')Unix time launch started Xenia at; infinity until it does.
Infinity rather than zero so an instance that never launched matches
no file at all. Zero is newer than nothing, so every title in the
container would read as written this session and save_and_exit
would restamp and ship all of them.
Functions
func__init__(self) -> NoneInitialise the process handle and the session baseline.
paramselfReturns
Nonefunc_stale_save_dirs(self) -> list[Path]Saved-game trees left in the content tree by an earlier session.
Scoped the way _session_title_dirs scopes the dump: only
<XUID>/<TITLE_ID> pairs count as save data, and the profile package
is skipped. Every XUID and every title id is swept, not just the
incoming one, because a directory named for another account or another
game holds the last player's saves just the same, and the exit restamp
ships a touched title whole.
paramselfReturns
listThe directories to remove, empty when there is no content tree,
funcclear_working_slot(self, excluded=()) -> NoneDrop the previous session's saved games before the archive restore.
The restore only writes the members this player's archive names, so a save the last player left behind would otherwise sit in the content tree readable by this one, and leave again in this player's own dump: the exit restamp ships a title whole once anything under it is written.
Only the saved-game content type and its header sidecars go. Installed DLC and title updates share the title directory, the profile package the save paths are keyed by has to survive for the next launch to sign in at all, and config, cache and shader dumps sit beside the content tree; none of that is a player's data.
paramselfparamexcludedtuple[str, ...]= ()Subtrees carried by the whole-card routes. Xenia names no memory card subtree, so this is always empty.
Returns
Nonefuncalways_restore(self, rel) -> boolWhether rel is a profile member, restored over whatever is on disk.
The clear leaves the profile package in place, so at restore time it is still the last player's, carrying the mtime the exit restamp gave it (the profile rides along with any title that saved, so it is routinely the freshest thing in the tree). The incoming archive's profile is older by construction, since it was taken in this player's previous session, and the newer-file guard would pass it over: the session would run, and then dump, under the last player's identity, propagating it to every player after them.
The guard does not describe this file. It exists so a restore cannot roll back progress made since the archive was taken, and a profile package holds no progress: nothing between the last dump and this restore wrote it, since the clear and the restore both run before the emulator boots.
paramselfparamrelstrThe member path, relative to save_root and posix-separated.
Returns
boolTrue for a file under content/<XUID>/FFFE07D1.
funcimport_spec(self) -> imports.ImportSpecDeclare what Xenia takes: saved games in the directory form, with their headers.
Xenia has no states and no cards, so the save kind is the only one.
paramselfReturns
webstation_broker.imports.ImportSpecThe spec.
func_profile_xuid(self, ctx) -> Optional[str]Read the signed-in profile's XUID, once per preflight.
This is the one file a placement hook reads. It sits outside the save subtrees and is only read, and preflight runs before anything is cleared or restored.
paramselfparamctximports.ImportCtxThe launch context; its memo holds the answer.
Returns
typing.OptionalThe XUID, or None when no single profile is signed in.
funcplace_import(self, member, spec, ctx) -> Union[imports.Placement, imports.ImportRefusal]Place one declared save file under the signed-in profile.
paramselfparammemberimports.ImportMemberThe member, already past the kind gate.
paramspecimports.ImportSpecThis emulator's spec.
paramctximports.ImportCtxThe launch context.
Returns
typing.UnionThe placement, or a refusal.
funcidentity_source(self) -> Optional[imports.IdentitySource]Read the title id off a container path, or take RomM's.
paramselfReturns
typing.OptionalA hex8 source that reads the rom's path through _rom_title_id.
funcresolve_rom_file(self, path) -> Optional[Path]Resolve a library entry to the file Xenia should boot.
A file is returned as given. A directory is resolved in order: an extracted dump's default.xex, then the best disc image or bare executable candidate, then an XBLA/Games on Demand content package.
paramselfparampathPathThe ROM library entry, either a bootable file or a directory to search.
Returns
typing.OptionalThe path to boot, or None if nothing bootable was found or a
funclaunch(self, rom_path, resume_slot) -> NoneStop any running instance and launch Xenia against a ROM.
Xenia has no save states, so resume_slot is accepted for interface parity with other emulators but only logged, never acted on; the game always resumes from its own save data.
paramselfparamrom_pathPathThe resolved ROM file to boot.
paramresume_slotOptional[int]Ignored save-state slot, kept for interface parity.
Returns
Nonefunc_session_title_dirs(self) -> list[Path]Content title dirs to ship whole, given what this session wrote.
A 360 save is a directory tree under
content/<XUID>/<TITLE_ID>/<CONTENT_TYPE>/<name> whose STFS header
lives in a sibling Headers tree the guest only writes when the save
is created. Scoping the dump to individually touched files would leave
that header behind and restore a save the guest cannot name, so the
title directory is the smallest unit that stays consistent.
The profile under <XUID>/FFFE07D1 joins any XUID that wrote
something, touched or not: save paths embed the XUID, so saves
restored without their profile land under an account the target
container has never signed in.
A listing or walk that fails is logged and skipped rather than raised: the storage root can vanish under the walk, and the exit path calling this still has a report to hand back.
paramselfReturns
listThe content/<XUID>/<TITLE_ID> directories to restamp, empty when
funcsave_and_exit(self, slot) -> dict[str, Any]Stop Xenia and mark this session's content for the dump.
paramselfparamslotOptional[int]Ignored; Xenia has no save states.
Returns
dictstate_saved, state_slot and state_file, all None.