Skip to content

iOS launcher: cloud saves refuse a folder inside the app, and one that cannot be written - #785

Closed
stephenschloesser wants to merge 1 commit into
seedds:mainfrom
stephenschloesser:cloud-saves-picker-copy
Closed

stephenschloesser wants to merge 1 commit into
seedds:mainfrom
stephenschloesser:cloud-saves-picker-copy

Conversation

@stephenschloesser

Copy link
Copy Markdown
Contributor

What and why

The iPhone launcher's Cloud saves section said the folder was set, and no save ever reached iCloud Drive, when the app runs from a live container (LiveContainer) or when the folder picked was the app's own Documents. Both are the same fault: the folder kept is inside the app's own storage.

A document picker in import mode copies what is picked into the app's Inbox instead of opening the folder where it is. A launcher's file-picker fix puts every picker of a guest app in that mode — LiveContainer's per-app Fix File Picker (doSymlinkInbox) makes TweakLoader/DocumentPicker.m pass asCopy:YES, and LCBootstrap.m links that Inbox under the guest's home and temp folder — so the "folder" the player picked is <container>/Inbox/<name>. dm_store_cloud_saves asked the system for a bookmark of whatever URL came back and stored it. A bookmark of a copy resolves and writes as well as a real one, so every save went to <container>/Inbox/<name>/<title ID>/save.dmsync, on the device, while the launcher showed the folder's name and the game logged boot: cloud saves through …. UIFileSharingEnabled puts the app's own Documents in the Files app, so the same mistake is one pick away by hand. The second way a save stops before iCloud Drive is a folder the app cannot write to: the host writes the save there after every save, and nothing checked that it could.

The change judges the folder before it is kept. dm_cloud_saves_problem (CloudSaves.m) refuses one inside the app's own storage — Documents, the Inbox, temp, compared as paths and with symlinks resolved, which is how a guest's linked Inbox is caught — and, at a pick, one the app cannot write a .nosync check file into. dm_store_cloud_saves returns that sentence for the launcher's footer instead of storing the folder, and dm_cloud_saves_path applies the same rule to a folder read back at boot, so a bookmark an older build stored for a copy is logged ([RED] boot: the picked cloud-save folder cannot be used: …) and not used. The player turns Fix File Picker off for the app in its launcher and picks the iCloud Drive folder again; Documents/env.txt with DM_SAVE_SYNC=<absolute path> sets the folder without a picker at all, which is what a build whose picker cannot deliver a real folder needs.

Reference entry added: Cloud saves shows a folder, and no save reaches iCloud Drive. The launcher section that shows the reason is the iPhone's only (dm/mac/Launcher.swift picks with an NSOpenPanel and copies nothing).

Checked

  • Tests: dm/ios/tests/test_cloud_saves.py (new) compiles CloudSaves.m on macOS and runs the real function on a fixture container: a folder in Documents, in the Inbox, in temp and behind an Inbox symlink are refused at a pick and at boot; a read-only folder is refused at a pick (cannot be written to) and kept at boot, where a write failure is a moment's problem; a file and a missing path are refused; a writable folder outside is accepted and the .nosync check file is gone again. dm/ios/tools/compile_check.py (iPhone SDK, 185 files, 0 failed) and the Swift typecheck of Launcher.swift with the bridging header pass. python3 -m unittest dm.tools.tests.test_docs passes after dm/tools/docs_symptoms.py, and dm/tools/lint_python.py reports 0 new findings. The other dm/ios/tests pass, except test_xcode_workflow.py, which fails the same six cases on a clean origin/main worktree here (local tooling, not this diff).
  • Games run, with title ID and version: none. The diff is the launcher's folder check, before the host starts, and no host, gfx or chain file is in it, so how a game runs is unchanged. What does change is a game whose cloud-saves folder was a copy: it now starts without cloud saves and the launcher says why, instead of sending every save into the app.
  • Devices and OS: no device ran this. The cause was read from LiveContainer's source (TweakLoader/DocumentPicker.m, LCBootstrap.m, LiveContainerSwiftUI/Views/AppList/AppSettings/LCAppSettingsView.swift for the Fix File Picker toggle) and its FAQ's "file picker not working" entry, not from an iPhone run; the folder rules are exercised on macOS only.
  • regress.py impact origin/main..HEAD: maps the three iOS files to *:*, so it names every game. No check --games run, for the reason in the bullet above.
  • Measurements before and after: not a speed, memory or power change.
  • Not checked: any iPhone or iPad run; LiveContainer's copy mode end to end (whether asCopy:YES on a folder still hands back a copy on current iOS — the rule refuses any folder the app owns, whatever made it); a folder in a third-party provider (Dropbox, Google Drive).

Docs

  • Finding in its reference entry (docs/reference/services.md, save-data section) with docs_symptoms.py run; docs/settings.md says what the launcher refuses and points at DM_SAVE_SYNC in an env.txt.
  • Chain tool changed → dmsh_chain.py --header run and dmsh_chain.h included — not applicable, no chain tool changed.
  • No game files, keys or data extracted from a game.

The launcher's Cloud saves section kept whatever folder the document picker
handed back. A picker in import mode hands back a copy inside the app, and a
launcher's file-picker fix puts every picker of a guest app in that mode
(LiveContainer's Fix File Picker, TweakLoader/DocumentPicker.m forces asCopy),
so the folder was <container>/Inbox/<name>: a bookmark of it resolves and
writes as well as a real one, every save stayed on the device, and the
launcher said cloud saves was on. The app's own Documents is the same mistake
made by hand. A folder the app cannot write to is the other way a save stops
before iCloud Drive.

dm_cloud_saves_problem now judges a folder before it is stored: one inside the
app's own storage (Documents, Inbox and temp, compared as paths and with
symlinks resolved, which is how a guest's linked Inbox is caught) and one the
app cannot write a .nosync check file into are refused, with the sentence the
launcher shows under Cloud saves. dm_cloud_saves_path applies the same rule to
a folder read back at boot, so a bookmark an older build stored for a copy is
logged ([RED] boot: the picked cloud-save folder cannot be used) and not used.
The player turns Fix File Picker off for the app and picks the iCloud Drive
folder again; Documents/env.txt with DM_SAVE_SYNC sets the folder without a
picker.

Validation: dm/ios/tests/test_cloud_saves.py compiles CloudSaves.m on macOS
and checks a folder in the app, a folder behind an Inbox link, a read-only
folder, a file and a missing path; the iOS compile check (185 files), the
Swift typecheck of the launcher with the bridging header, dm/tools/test_docs
and the Python lint ratchet pass. No device ran this change.
@stephenschloesser
stephenschloesser deleted the cloud-saves-picker-copy branch October 31, 2026 10:43
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.

2 participants