An APK missing any asset GameAssets.kt opens by name installs and launches
fine, then fails on the device during staging — which is how two of them
reached test builds already. Fail the job instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GenerateBuilds runs on every push and builds six platforms, which is a long
wait when all you want is an APK to sideload. This builds ghostship.o2r and a
debug APK on its own, on demand or when something the APK contains changes.
Not for the upstream PR either — GenerateBuilds already has a build-android
job. This exists to shorten the device-test loop.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An APK missing any asset GameAssets.kt opens by name installs and launches
fine, then fails on the device during staging — losing the game data to an
asset merge that had nothing to merge, or a source file to gitignore, both
left the build green. Fail the job instead of shipping it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The player no longer needs a PC. LauncherActivity unpacks the bundled data,
takes a ROM through the document picker, checks it against the supported
SHA-1s, and runs Torch through JNI to produce sm64.o2r — about 27s on a
Pixel 10a. The archive is byte-identical to a host extraction.
GameExtractor gains a GenerateOTRTo() overload taking the two directories
explicitly: the launcher runs before SDL exists, so Ship::Context cannot
resolve a path yet.
The launcher runs in its own process and ends it once the archive is written.
Torch's Companion is deliberately never freed — every platform leaks it, and
its destructor does not survive being run — so ending the process is what
returns that memory before the game starts.
Unpacking the packaged data moves from the engine to the launcher, because
Torch needs config.yml and assets/ymls on disk before the game process starts,
not after. It is the same gamedata.zip from the same Gradle tasks, so the
packaging and the CI artifact are unchanged; AndroidUtils.cpp goes away.
Also adds mods and saves managers behind a button that appears while the
engine menu is open, and fixes edge-to-edge: with targetSdk 36 the system
ignores the old fullscreen flags, so the navigation bar was sitting on top of
the game.
Toolchain moves to NDK 30.0.15729638, SDK 36, Gradle 8.13, AGP 8.13.2 and the
Kotlin DSL, and builds arm64-v8a and armeabi-v7a. CMAKE_BUILD_TYPE=Release is
forced for every variant: the Android plugin builds the release variant as
RelWithDebInfo (-O2), but the root CMakeLists pins Release to -O1
-fno-strict-aliasing because the game's C code is miscompiled above that.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>