Skip to content

Feat: Shared app export without a build, send every game's data and shaders - #1080

Closed
Absenti wants to merge 1 commit into
LNPANDY:mainfrom
Absenti:shared-app-export-every-game
Closed

Absenti wants to merge 1 commit into
LNPANDY:mainfrom
Absenti:shared-app-export-every-game

Conversation

@Absenti

@Absenti Absenti commented Nov 9, 2026

Copy link
Copy Markdown

Fix or feature

  • Fix
  • Feature

Feature from outside: #994 has no milestone yet. It needs a maintainer's yes before this can merge.

Tested locally

What and why

Closes #994 . Fixes #947 .

Problem. Making the shared app's IPA again meant building a game first ("Export IPA" builds), and step 3 sent only the game just built. The shaders made the IPA too big for SideStore: Ocarina of Time's are 7 GB in one file (#947 ).

Change. "Export these games" makes the IPA from the games built before, with no build. Step 3 sends every game's data, with a tick per game. The export moves each game's msl/ out of the IPA into its data folder, and step 3 sends it with romfs.img.

Details
  • shell.json records each game's data folder at build time; older games are found from the library (ShellGameData).
  • Step 1's button says "Build and export". "Export these games" stays after an export. The stale-shader prompt asks before it too.
  • Step 3 keeps the ticks, and names the games whose data is not on this Mac.
  • SideStore's archive reader (SideSign Archive.swift) has no ZIP64 and loads each file whole into memory: it fails past 4 GB and closes on a 2 GB file.
  • The msl/ copy is an APFS clone, skipped when unchanged. A game with no recorded data folder keeps its shaders in the IPA.
  • The shell reads Documents/games/<title ID>/msl already; it now also reads msl/ beside a data folder picked elsewhere.

Checked

  • Tests: frontend 922, frontend-ios 242, frontend-qt 420, all pass. Rebased on main after frontend: show iPhone activity title and preserve library state during iOS re-sign #1028.
  • Test for a fix: the shaders leaving the IPA (with and without a recorded data folder), and the shell reading msl/ beside the data.
  • Visual QA: NX_LAUNCHER_CAPTURE_DIR captures of the export card, below.
  • Run on a device or Mac: MacBook Pro M1 Pro, macOS 27.2; iPhone 15 Pro, SideStore 0.7.0. Ocarina of Time (0400486024DEC000) IPA 6.9 GB → 65 MB, installed, shaders read from Documents. Not checked: Windows (unchanged).

Screenshots

Before (main):
before-1-ready
before-2-exported

After:

after-1-ready after-2-exported

Scope

  • No engine file (dm/, scripts/, docs/, ref/) is added to the repository: a change there is a patch in patches/ (a commit in engine/, then tools/engine.py export, and tools/engine.py check passes), with its Upstream-Status
  • A fix to the engine or a game profile also goes to seedds/nxnative as a PR in parallel: this PR's patch says forwarded seedds/nxnative#..., or pending until that PR is open
  • A change to a launcher view has before and after screenshots above
  • No keys, game files or data extracted from a game in the change or the attachments

🤖 Generated with Claude Code

…ata, keep the shaders out of the IPA (LNPANDY#994)

Step 1 only built: making the IPA again (to add a game built earlier, or
after a fix) meant building the selected game first, under a button that
said "Export IPA". Step 3 sent the data of the game just built only.
And the shader libraries made most of the IPA: Ocarina of Time's is
7 GB in one file, which SideStore cannot read (its archive reader has no
ZIP64 and loads each file whole into memory), so the IPA did not
install (LNPANDY#947).

- shell.json records each game's data folder when the game is built;
  a game built before that is found from the launcher's library (its
  build folder, its inputs: ShellGameData).
- "Export these games" under step 1 makes the IPA from the games built
  before, with no build, and stays after an export. Step 1's own button
  says what it does: "Build and export". The stale-shader prompt asks
  before an export without a build too.
- Step 3 sends the data of every game of the app, to the device or a
  drive, with a tick per game (kept), and names the games whose data is
  not on this Mac.
- The export leaves each game's msl/ out of the IPA and puts it in the
  game's data folder (an APFS clone, skipped when unchanged); step 3
  sends it with romfs.img. The shell reads Documents/games/<title ID>/msl
  already, and now msl/ beside a data folder picked elsewhere too. A
  game with no recorded data folder keeps its shaders in the IPA.

Checked on a MacBook Pro M1 Pro (macOS 27.2) and an iPhone 15 Pro with
SideStore 0.7.0: Ocarina's IPA went from 6.9 GB to 65 MB and installed,
and the shell took its shaders from Documents. Tests cover the export
without a build, the data folders, the send of every game with ticks,
and the shaders leaving the IPA.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added launcher The NX2Apple launcher app ios iPhone or iPad windows Windows (the Qt front end) labels Nov 9, 2026
@Absenti Absenti changed the title Feat: Shared app: export without a build, send every game's data and shaders Feat: Shared app export without a build, send every game's data and shaders Nov 9, 2026
@v0lumehi v0lumehi modified the milestones: v1.4.0, v1.5.0 Nov 12, 2026
@LNPANDY

LNPANDY commented Nov 13, 2026

Copy link
Copy Markdown
Owner

Closing as bulk data and shader export is being integrated into the native batch refresh and build queue workflow. Thank you for your work on this!

@LNPANDY LNPANDY closed this Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ios iPhone or iPad launcher The NX2Apple launcher app windows Windows (the Qt front end)

Projects

None yet

3 participants