Repository navigation
Conversation
Restores libultraship as a submodule at upstream's pin (eaaf9d0) instead of
the ~60k-line vendored copy this fork carried. Every fork patch in that copy
was audited and found superseded, dead, or an artifact of the old Android
flow:
- os_eeprom.cpp's Android_GetSaveDir() hook is replaced by upstream's
Ship::Context::GetPathRelativeToAppDirectory("default.sav")
- interpreter.cpp's upfront 64MB posix_memalign buffer is replaced by
upstream's lazy allocation at the real max texture size
- MobileImpl's touch-area/camera additions and the Gui.cpp calls into them
are unused by Starship; the on-screen controller becomes a virtual SDL
joystick instead
- gfxbridge.h differed only in line endings, OTR_ARCHIVE_INCLUDED was never
referenced, and CrashHandler.h was already identical
Engine.cpp takes upstream's constructor ordering, which drops the Android
waitForSetupFromNative() polling: the launcher now generates sf64.o2r before
the game starts, so there is nothing to wait for. Android keeps only the
fullscreen default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The app used to require an sf64.o2r the user had produced on a PC with
Torch, then hand it over through a SAF folder grant backed by
MANAGE_EXTERNAL_STORAGE. Now the launcher takes the ROM itself, verifies
it, and runs Torch — already linked into the game library — to build the
archive on the device. No storage permission, no desktop step.
The app is rebuilt in Kotlin around that flow, matching Ghostship and
SpaghettiKart:
LauncherActivity unpack bundled files, take a ROM, extract, hand off
GameAssets where everything lives, plus the JNI extraction call
MainActivity the game and the on-screen controller overlay
Mods/SavesActivity managers reachable from the in-game menu
The overlay drives a virtual SDL joystick (src/port/android/AndroidBridge.cpp)
instead of synthesising input, so it goes through libultraship's normal
mapping and is remappable in game. That also replaces the look-around
area's old route into a fork-only libultraship camera API, which went
away with the vendored copy: it now drives the right stick.
Build side:
- Groovy -> Kotlin DSL, AGP 8.13.2, Kotlin 2.2.10, NDK 30.0.15729638
- config.yml, assets/yaml/ and starship.o2r are bundled as one
reproducible gamedata.zip with a digest beside it, wired through the
variant API so a missing engine archive fails the build loudly rather
than shipping an APK with nothing in it
- cmake/dependencies/android.cmake supplies what the NDK build has no
package manager for. libultraship's own Android cmake only fetches
SDL2 and leaves libzip, nlohmann_json, tinyxml2 and spdlog to one.
It also pins SDL 2.32.10, because the 2.28.1 libultraship asks for
calls ALooper_pollAll, which NDK 27 removed from the headers; the
Java glue's SDL_MICRO_VERSION moves with it or SDLActivity refuses
to start. Ogg and Vorbis are fetched too — the Android branch of the
platform switch links them but never had a find_package.
- the host-only Torch ExternalProject, the asset copy next to the
binary and CPack are all skipped on Android
- .gitignore's "build*" was swallowing build.gradle.kts
Verified: libStarship.so builds clean for arm64-v8a from an empty build
directory, and exports all six JNI entry points the Kotlin side declares.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The debug variant compiled 590 native files, Torch's Companion.cpp among them, with no -O flag at all: the root CMakeLists sets CMAKE_C_FLAGS_RELEASE but nothing for Debug, so Debug fell through to the compiler default of -O0. That was survivable while Torch ran on a PC. It is not now that it runs on the phone. Extraction is STL-heavy work over a 12MB ROM, and unoptimised it made no visible progress — a profile of the stuck thread showed a bounded ~11-level recursion through Companion::ParseNode into the audio factories, burning effectively all of its time in std::vector<uint8_t> copy and destroy. Not a hang; just far too slow to ever finish. Forcing Release for every variant resolves to -O2 -DNDEBUG on Android. Extraction then completes in 74s on a Pixel 10a and the game boots. isJniDebuggable goes with it: the native side is Release regardless now, so there is nothing useful left to attach to. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three fixes found by running the game on a device. The overlay's Menu button did nothing. libultraship drives two separate things (Gui::DrawMenu): Escape toggles a "Menu", F1 toggles a "MenuBar". SpaghettiKart installs a Menu, so its overlay sends Escape, and that is what this button was copied from. Starship installs a menu bar instead — ImguiUI.cpp calls SetMenuBar() and never SetMenu() — so GetMenu() was null and Escape was a no-op. F1 is also what the game's own hint tells players to press. isMenuOpen() already read GetMenuOrMenubarVisible(), which covers both, so the Mods button appearing with the menu kept working throughout. add_subdirectory(libultraship) passed libultraship's own source directory as its binary directory, which put libImGui.a and libstb.a in the source tree. With one architecture that is untidy; Android builds every ABI from the same tree, so the two raced over those archives and the arm64 link failed on armeabi-v7a objects. It only linked at all the first time by winning that race. Given a binary directory of its own, scoped to Android so nothing else changes. The mods and saves screens never applied window insets — the title sat under the status bar and "Done" was half behind the navigation bar. They came from SpaghettiKart, which has no padForSystemBars(); Ghostship calls it in all three activities, and now so does this. The saves screen also still described Controller Pak data, which Star Fox 64 does not have. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Updated contact information from Discord to official website.
Move the game directory from Android/data to Android/media so Syncthing and other file syncers can reach saves without special access. MainActivity overrides getExternalFilesDir(null) so the engine's SDL path lookup lands in the same directory the launcher uses.
Android port from izzy2lost/Starship, merged with HarbourMasters/Starship main (up to 3322643), plus saves and game files moved from Android/data to Android/media so Syncthing can reach them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Syncthing and other file syncers can reach them. MainActivity overrides
getExternalFilesDir(null) so the engine's SDL path lookup matches the
launcher's game directory.
'tools' SDK package (use sdkmanager from PATH)
Existing installs are not migrated: saves, the ROM and sf64.o2r stay in
the old Android/data folder.