Skip to content

Add partial iOS support and fix most race-entry crashes#684

Open
ykr2byfrqb-wq wants to merge 12 commits intoHarbourMasters:mainfrom
ykr2byfrqb-wq:ios-partial-support
Open

Add partial iOS support and fix most race-entry crashes#684
ykr2byfrqb-wq wants to merge 12 commits intoHarbourMasters:mainfrom
ykr2byfrqb-wq:ios-partial-support

Conversation

@ykr2byfrqb-wq
Copy link
Copy Markdown

@ykr2byfrqb-wq ykr2byfrqb-wq commented Apr 6, 2026

Summary

This PR brings the current iOS work together into one source-only branch.

Right now, the practical workaround for the remaining track crashes is to install the official MK64 Reloaded SpaghettiKart .o2r through the normal mods folder workflow on iPhone. With that mod in place, the current IPA works properly in on-device testing.

This PR also includes the libultraship submodule update required for the iOS changes, but it does not include any ROM assets, Nintendo content, or bundled third-party mod files.

iPhone Setup

  • download the official MK64 Reloaded SpaghettiKart .o2r
  • copy the .o2r file into Spaghettify/mods on the iPhone
  • launch the app after the file is in the mods folder

Build IPA

Prerequisites:

  • macOS with Xcode installed
  • CMake available in PATH
  • your own supported Mario Kart 64 ROM

Build steps:

  1. clone this branch and update submodules
    git clone --recurse-submodules <your-fork-or-branch-url>
  2. if you already cloned without submodules, run:
    git submodule update --init --recursive
  3. generate the base asset archives from your own ROM:
    • place your ROM where the project can use it as baserom.us.z64
    • generate the asset archives with:
      cmake -S . -B build-cmake -GNinja
      cmake --build build-cmake --target ExtractAssets
    • this produces the required mk64.o2r and spaghetti.o2r archives from your own ROM data
  4. configure the iOS build:
    cmake -S . -B build-ios-make -DCMAKE_BUILD_TYPE=Release -DIOS=ON -DSIGN_LIBRARY=OFF
  5. build the app:
    cmake --build build-ios-make --config Release
  6. package an unsigned IPA:
    mkdir -p build-ios-make/Payload
    rm -rf build-ios-make/Payload/Spaghettify.app
    cp -R build-ios-make/Spaghettify.app build-ios-make/Payload/Spaghettify.app
    rm -f build-ios-make/SpaghettiKart-unsigned.ipa
    zip -qry build-ios-make/SpaghettiKart-unsigned.ipa build-ios-make/Payload
  7. the resulting unsigned IPA will be at:
    build-ios-make/SpaghettiKart-unsigned.ipa

Asset Notes

  • the build requires user-generated mk64.o2r and spaghetti.o2r files
  • those files are generated from a user-provided supported Mario Kart 64 ROM
  • this PR does not include those archives or any ROM-derived content
  • on iOS, if the app still needs the ROM directly for extraction, the ROM filename expected by the app is baserom.us.z64

Current iOS status

  • testing on-device shows the current IPA works properly when MK64 Reloaded is added to the app's mods folder
  • this is a temporary workaround while the underlying track crash is still being investigated

Notes

  • This PR does not include any copyrighted Nintendo assets
  • This PR does not bundle MK64 Reloaded or any other third-party asset pack
  • Users must provide their own supported Mario Kart 64 ROM to build and run the project
  • Depends on Add partial iOS support Kenix3/libultraship#1056 for the submodule update

}

std::vector<std::string> ListMods() {
const std::string main_path = Ship::Context::GetPathRelativeToAppDirectory(game_asset_file);
Copy link
Copy Markdown
Contributor

@coco875 coco875 Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about this change

Copy link
Copy Markdown
Contributor

@MegaMech MegaMech Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this file feel like feature changes to me.

Prefer if this sort of change was discussed in the PR description (here is fine now) as to why/what this improves. Separate PR best but not required.

Copy link
Copy Markdown
Contributor

@coco875 coco875 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe clean a bit more debug or make it a bit more general ?

Comment thread src/engine/RaceManager.cpp Outdated
}
}
}
#ifndef __IOS__
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why it's needed ? can you add a comment

Comment thread src/port/Game.cpp Outdated
}

void CM_TickEditor() {
#ifdef __IOS__
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like you disable editor for ios

// Mobile: fallback to baserom.us.z64
if (!foundGame && !std::filesystem::exists(Ship::Context::GetPathRelativeToAppDirectory("baserom.us.z64"))) {
SPDLOG_ERROR("baserom not found");
// Mobile: fallback to baserom.us.z64 in the writable app directory.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm maybe would be better to use the system that search for a rom with the correct hash in a folder like on pc ?

@ykr2byfrqb-wq
Copy link
Copy Markdown
Author

Cleaned this up.

  • removed the temporary iOS race debug instrumentation
  • removed the iOS-only editor tick/draw disable
  • replaced the iOS-specific gEditor.AddLight skip with an editor-enabled check instead
  • kept the current iOS actor/static-mesh render skips, but added comments since those are still part of the active crash workaround
  • also cleaned up the stray TargetConditionals.h include in the dependent libultraship PR

The libultraship update is now at Kenix3/libultraship#1056.

Comment thread include/mk64.h
#define STACKSIZE 0x2000
#else
#define STACKSIZE 0x10000
#endif
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert, the stacks are unused

}

std::vector<std::string> ListMods() {
const std::string main_path = Ship::Context::GetPathRelativeToAppDirectory(game_asset_file);
Copy link
Copy Markdown
Contributor

@MegaMech MegaMech Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this file feel like feature changes to me.

Prefer if this sort of change was discussed in the PR description (here is fine now) as to why/what this improves. Separate PR best but not required.


if (gEditor.IsEnabled()) {
gEditor.AddLight("Sun", nullptr, D_800DC610[1].l->l.dir);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good!

TrackSections* TrackSectionsClass::GetPointer() {
return TrackSectionsList.data();
PointerData = TrackSectionsList;
PointerData.push_back({});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the pushback of a blank array?

std::vector<TrackSections> TrackSectionsList;

private:
std::vector<TrackSections> PointerData;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, but why is this change necessary?
Isn't it the same as TrackSectionsList?

Comment thread src/port/pak.cpp
return Ship::Context::GetPathRelativeToAppDirectory(fmt::format("controllerPak_file_{}.sav", file_no));
#else
return Ship::Context::GetPathRelativeToAppDirectory("controllerPak_file_" + std::to_string(file_no) + ".sav");
#endif
Copy link
Copy Markdown
Contributor

@MegaMech MegaMech Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering if we should just use the second variation for everything and remove the format.h include and the ifdef?

Comment thread CMakeLists.txt
"src/port/*.h"
"src/port/*.c"
"src/port/*.cpp"
"src/port/*.mm"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is .mm?

Comment thread CMakeLists.txt
set(STORYBOARD_FILE ${IOS_DIR}/Launch.storyboard)
set(IMAGE_FILES ${IOS_DIR}/PoweredBy.png)
set(ICON_FILES ${IOS_DIR}/Icon.png)
set(ICON_FILES ${CMAKE_CURRENT_SOURCE_DIR}/icon.png)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why image files removed? Not used?

@MegaMech
Copy link
Copy Markdown
Contributor

MegaMech commented Apr 11, 2026

One idea for the editor stuff. I believe switch and android remove the editor (iirc). Since this also does not need the editor,

we could

  1. Skip enabling the editor
  2. Add the if editor enabled check to the tick/draw
  3. Add some sort of IsMobile() check behind the tick/draw

I'm also fine with the way it is for now. Perhaps change the define to IS_MOBILE or IS_HANDHELD_DEVICE or similar instead?

I think editor tick/draw also tests for editor enabled in those functions (but I don't remember)

@MegaMech
Copy link
Copy Markdown
Contributor

The issue with the normal game assets not working was likely fixed in the latest lus version.

@coco875
Copy link
Copy Markdown
Contributor

coco875 commented Apr 11, 2026

and have been confirmed by the creator of the pr so it's not longer an issue

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.

3 participants