webstation-broker
DeveloperPython referenceemulatorsemulators.xenia

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
= True

On; with the ROM cache enabled, launch boots a local copy of the ROM.

attributedisplay_name
= 'Xenia'

Human-readable name.

attributesave_root
= DATA_DIR

The storage root the save subtrees hang off.

attributesave_subtrees
= (CONTENT_SUBTREE,)

content, the save and profile tree.

attributerom_extensions
= ROM_EXTENSIONS

Bootable formats, best first.

attributelog_path
= XENIA_LOG_PATH

The emulator log file.

attributeclears_stale_saves
= True

On; 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) -> None

Initialise the process handle and the session baseline.

paramself

Returns

None
func_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.

paramself

Returns

list

The directories to remove, empty when there is no content tree,

funcclear_working_slot(self, excluded=()) -> None

Drop 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.

paramself
paramexcludedtuple[str, ...]
= ()

Subtrees carried by the whole-card routes. Xenia names no memory card subtree, so this is always empty.

Returns

None
funcalways_restore(self, rel) -> bool

Whether 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.

paramself
paramrelstr

The member path, relative to save_root and posix-separated.

Returns

bool

True for a file under content/<XUID>/FFFE07D1.

funcimport_spec(self) -> imports.ImportSpec

Declare 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.

paramself

Returns

webstation_broker.imports.ImportSpec

The 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.

paramself
paramctximports.ImportCtx

The launch context; its memo holds the answer.

Returns

typing.Optional

The 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.

paramself
parammemberimports.ImportMember

The member, already past the kind gate.

paramspecimports.ImportSpec

This emulator's spec.

paramctximports.ImportCtx

The launch context.

Returns

typing.Union

The placement, or a refusal.

funcidentity_source(self) -> Optional[imports.IdentitySource]

Read the title id off a container path, or take RomM's.

paramself

Returns

typing.Optional

A 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.

paramself
parampathPath

The ROM library entry, either a bootable file or a directory to search.

Returns

typing.Optional

The path to boot, or None if nothing bootable was found or a

funclaunch(self, rom_path, resume_slot) -> None

Stop 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.

paramself
paramrom_pathPath

The resolved ROM file to boot.

paramresume_slotOptional[int]

Ignored save-state slot, kept for interface parity.

Returns

None
func_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.

paramself

Returns

list

The 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.

paramself
paramslotOptional[int]

Ignored; Xenia has no save states.

Returns

dict

state_saved, state_slot and state_file, all None.

On this page