Skip to content

fix(launcher): a game on an external drive waits for macOS's answer before the engine starts - #122

Merged
utkuhalis merged 1 commit into
mainfrom
fix/external-volume-first-run
Nov 12, 2026
Merged

utkuhalis merged 1 commit into
mainfrom
fix/external-volume-first-run

Conversation

@utkuhalis

Copy link
Copy Markdown
Collaborator

What

The Mac launcher, for a games folder on an external drive (refs #120).

The launcher opens a game's bundle through NSWorkspace (AppModel.start), so macOS treats the game as its own app, and that bundle and its files are in the games folder's .AnyPS5 store, on the drive itself (Installer.bundle(for:root:), Installer.dataFolder). The bundle is unsigned. So the game's first reads of the drive raise macOS's "would like to access files on a removable volume" prompt. The launcher has already been reading and writing the folder, so the launcher does not get the prompt. The game does, which is why the report lists the game in Files and Folders and not AnyPS5. Until now the launch script's first step was a cd into the drive, followed by exec of the engine. No step waited for the player's answer.

With this change the launch script reads the game's app0/sce_sys/param.json first, before any cd into the drive. Every game the launcher lists has that file. If the read fails, the script tries again every 0.2 s for up to two minutes, then goes on as before. The engine starts once the read gets through, so the game's own reads come after the player has answered. A folder on the internal disk reads at once and starts as before. A copy unlocked by an older launcher picks up the new script when it is rebuilt, which an engine update does before the next start.

Not done here: the prompt still comes back after every rebuild, and maybe on every start, because the bundle has no signature that macOS could tie the permission to. Relinked executables are not signed, so that stays as it is.

Tested

  • Not tested on hardware with an external drive. Nobody here could check what macOS does to a read while its prompt is still open.
  • New LaunchScriptTests run the generated script the way macOS starts a bundle (through its #! line). A param.json without read permission stands in for the read macOS holds back. The tests check that a readable game starts at once in its game folder, that the engine waits until the file becomes readable, that a read that never gets through still starts the game after the wait, and that the read comes before any cd. They run in CI.
  • sh -n on the generated head, plus one manual run of it with the file unreadable for one second.
  • python3 tools/check_conventions.py --base origin/main passed.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none (refs Crash: Hollow Knight: Silksong (PPSA12544 v01.000.010) SIGSEGV at eboot+0x15ac117 (address 0x88) on Apple M5 Max #120, to be closed once the reporter confirms)
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

…efore the engine starts

A games folder on an external drive is a removable volume to macOS, and
the game runs there as its own app (opened through NSWorkspace, unsigned),
so its first reads of the drive bring up "would like to access files on a
removable volume". Until now the launch script's first step was a cd into
the drive and the engine started right after, so the game's own reads
could meet the prompt on the first start.

The launch script now reads the game's param.json first, before any cd
into the drive, and tries again every 0.2 s for up to two minutes until
the read gets through. The engine starts once the player has answered.
@utkuhalis
utkuhalis merged commit 52145a7 into main Nov 12, 2026
10 checks passed
@utkuhalis
utkuhalis deleted the fix/external-volume-first-run branch November 12, 2026 23:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant