webstation-broker
DeveloperPython referenceemulatorsemulators.shadps4

emulators.shadps4.Shadps4

PlayStation 4 via shadPS4, driven over its stdin IPC protocol.

PlayStation 4 via shadPS4, driven over its stdin IPC protocol.

The binary is picked from the launcher's versions tree at launch time and spawned fullscreen with SHADPS4_ENABLE_IPC=true and a stdin pipe. RUN then START are written straight away so the game boots without waiting on the RUN deadline, and the stop writes STOP, which pushes SDL_EVENT_QUIT, the same path as a window close. shadPS4 registers no SIGTERM/SIGINT handler, so a bare SIGTERM would kill it hard and leave read-write save mounts with their sce_sys/corrupted marker in place; SIGTERM is only the escalation after STOP times out or the pipe breaks.

There are no save states: persistence is the game's own save data under home/1000/savedata, keyed by game serial, which is what the archive carries. A resume slot is logged and ignored.

A .pkg ROM, or a .7z/.zip/.rar archive holding one, is unpacked through the CACHE_DIR extraction cache before boot, and is only bootable at all when that cache is enabled.

Attributes

attributename
= 'shadps4'

Provider key, shadps4.

attributedisplay_name
= 'shadPS4'

Human-readable name.

attributesave_root
= DATA_DIR

The data directory the save subtree hangs off.

attributesave_subtrees
= (SAVEDATA_SUBTREE,)

Save data plus its per-title param.sfo, under the default PS4 user.

attributeclears_stale_saves
= True

On; clear_working_slot empties the savedata subtree.

attributelog_path
= SHADPS4_LOG_PATH

The emulator log file.

attributeterm_timeout
= float(os.environ.get('SHADPS4_STOP_WAIT', '20'))

Seconds STOP gets before SIGTERM (env SHADPS4_STOP_WAIT, default 20).

attribute_graceful_exitOptional[bool]
= None

How the last stop of a live process went, None when none has run yet.

True only for an IPC STOP the emulator answered on its own. False once the SIGTERM escalation had to run, which shadPS4 has no handler for and so cannot flush its save mounts through.

attributerom_extensionstuple[str, ...]

Bootable formats, minus the ones needing the disabled extraction cache.

.pkg and the archive formats only reach a boot target by way of CACHE_DIR, so with the cache off they are not bootable and must not be advertised as accepted.

Functions

func__init__(self) -> None

Start with the base handles and no verdict on a shutdown yet.

paramself

Returns

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

Drop the previous session's save data before this session's restore.

There is no save state and no working slot to reset, so the whole of the clear is the savedata subtree (_clear_stale_save_data). It goes whole rather than scoped to the incoming serial: the exit dump ships the subtree, not the titles this session booted, so another title's leftovers would leave in this player's archive.

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

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

Returns

None
funcimport_spec(self) -> imports.ImportSpec

Declare what shadPS4 takes: one save folder per title, and never its mount marker.

paramself

Returns

webstation_broker.imports.ImportSpec

The spec.

funcplace_import(self, member, spec, ctx) -> Union[imports.Placement, imports.ImportRefusal]

File one declared save file under the default user's savedata.

paramself
parammemberimports.ImportMember

The member, already past the kind gate.

paramspecimports.ImportSpec

This emulator's spec.

paramctximports.ImportCtx

The launch context, for the session's serial.

Returns

typing.Union

The placement, or a refusal.

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

Take the session's serial from the game's param.sfo, then from RomM's title id.

paramself

Returns

typing.Optional

A ps_serial_nodash source reading the boot target's metadata,

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

The path shadPS4 should boot for path.

paramself
parampathPath

A ROM file, or a game folder.

Returns

typing.Optional

The file itself, the folder's eboot.bin, else the .pkg or

funclaunch(self, rom_path, resume_slot) -> None

Spawn the newest shadPS4 with IPC enabled and boot the game.

Raises

  • RuntimeError: When no binary is found under VERSIONS_DIR.
paramself
paramrom_pathPath

The file or folder to boot.

paramresume_slotOptional[int]

Ignored with a log line; shadPS4 has no save states.

Returns

None
func_ipc_send(self, cmd) -> bool

Write one IPC command line to the emulator's stdin.

paramself
paramcmdstr

The command, such as RUN or START; a newline is appended.

Returns

bool

True when the line was written and flushed, False when there is

funcstop(self) -> None

Ask shadPS4 to quit over IPC, escalating to the base SIGTERM stop.

STOP is written to stdin and the process given term_timeout to exit on its own; a broken pipe or a timeout falls through to the SIGTERM then SIGKILL sequence in the base class.

Which of the two ran is recorded in _graceful_exit for save_and_exit to report. shadPS4 registers no SIGTERM handler, so the escalation kills it wherever it happens to be, save mounts included; the save data the dump then ships cannot be trusted the way a clean IPC quit's can.

paramself

Returns

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

Stop shadPS4 and report whether the save data it leaves can be trusted.

There are no save states, so the state fields are always None. What this adds over the base is the shutdown's own verdict: the caller zips the save tree the moment this returns, and a stop that had to escalate to SIGTERM can leave a save half-written, with shadPS4's own sce_sys/corrupted marker the only sign of it.

paramself
paramslotOptional[int]

Ignored with a log line; shadPS4 has no save states.

Returns

dict

The state fields all None (state_saved, state_slot,

On this page