Peliarch Archipelago WIP fork of the Sunshine native PC port; player-owned disc required.
  • C++ 63.5%
  • Python 22.8%
  • C 6.2%
  • CMake 4.6%
  • Shell 2.3%
  • Other 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Alaric McKenzie-Boone 1a5bb36143 Publish Sunshine native Archipelago WIP source snapshot
Source tree of local 169b16cab7831fe1b5599d50ee87c89aa4554dc5; upstream chasem-dev/sms-pc-port base 831cdd97277ae3ac6696e8e81fda1dd732ff2f91. Native code ac40c4b; no game data included.
2026-10-14 13:40:03 -04:00
.github/workflows Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
assets Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
cmake Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
decomp@967436b8c6 Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
decomp-patches Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
docs Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
mods Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
platform Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
rom Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
src Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
tools Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
.gitattributes Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
.gitignore Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
.gitmodules Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
bindings.txt Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
build.cmd Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
BUILD.md Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
build.sh Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
clean.cmd Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
clean.sh Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
CMakeLists.txt Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
LICENSE Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
README.md Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
run-hd-cutscenes.sh Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
run.cmd Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
run.sh Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
settings.txt Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00
THIRD_PARTY_NOTICES.md Publish Sunshine native Archipelago WIP source snapshot 2026-10-14 13:40:03 -04:00

Join the Super Mario Sunshine Discord server
Join our Discord

sms-port

Archipelago Windows WIP

This fork contains an experimental native Windows x64 Archipelago integration. Setup, the supported seed profile, the client and the portable test package live in sunshine-archipelago. The bridge and save contract are documented in docs/AP_NATIVE_SPIKE.md. The complete normal campaign through Bowser has not been played through on this build. Rocket input/equip, partner delivery and normal save/reload have separate recorded checks; the native mechanism tests do not establish full campaign acceptance.

The published source snapshot retains native code revision ac40c4b and decompilation revision 967436b8c623834d38a57d34923775f45eca8861. The tested Windows executable SHA-256 is 6c4b58dce2e9774694ed9d7680f48ab9f1e7210007c47eb6ecf56adbb9217fb4. It reads your own GMSE01 Rev 0 disc image; no game image or extracted game data is included.

To build this WIP from source, use the Windows prerequisites in BUILD.md, clone this fork recursively, and run the following in MSYS2 MINGW64:

git clone --recursive --branch wip-2026-10-14 https://git.peliarch.ca/alaric/sunshine-pc-port.git
cd sunshine-pc-port
cmake -S . -B build/windows-64 -G Ninja -DSMS_ARCH=64 -DSMS_BUNDLE_DISC= -DSMS_GX_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build/windows-64 --target sms sms_ap_bridge_test
./build/windows-64/sms_ap_bridge_test.exe

Keep the pinned decomp/ revision when reproducing this build. For distribution builds, use bare CMake with an empty SMS_BUNDLE_DISC: SMS_STANDALONE=0 skips the bundled copy, but the upstream build script can still embed a game-derived Explorer icon when it discovers an image in rom/. The portable WIP executable was configured with SMS_BUNDLE_DISC= and contains only a manifest resource, without that icon or an embedded disc.

The port is MIT licensed; the decompilation has its own CC0 license. THIRD_PARTY_NOTICES.md preserves notices for code compiled into the port. The Windows runtime also needs SDL2, libgcc, libstdc++ and winpthreads. The portable package includes those DLLs and their notices; a source build uses the versions installed by MSYS2. Windows supplies the system graphics and audio DLLs.

A native PC port of Super Mario Sunshine (GameCube, North America, GMSE01), built from the matching decompilation.

No game data is included. You build the program from source, and it reads the models, textures, levels, music and movies from your own disc image at run time.

For guided setup, updates and a Play button, use our dedicated SMS Launcher for Windows, macOS and Linux. The launcher sets up this port on your computer using your own supported disc image; downloads are on its releases page.

Decompilation progress

GMSE01 progress: fuzzy similarity, byte-perfect code, and source-linked code

This card shows the GMSE01 decompilation snapshot recorded by the source revision pinned in this port. Fuzzy similarity measures approximate code similarity; the other two tracks show byte-perfect code and code linked from matching source.

Supported systems

System Word size Status Output
Linux (x86) 32-bit (default) plays build/linux-32/sms
Linux (x86-64) 64-bit (SMS_ARCH=64) plays; still being tested stage by stage (docs/64-BIT.md) build/linux-64/sms
macOS (Intel, or Apple Silicon under Rosetta 2) 64-bit plays build/macos-64/sms
Windows (MSYS2 MINGW64) 64-bit boots under Wine; native runtime checks build/windows-64/sms.exe

The game code keeps pointers in 4-byte fields, so it was written for a 32-bit machine. The 64-bit builds keep every address the game sees below 4 GiB; see docs/64-BIT.md.

Quick start

  1. Get the source, including the decompilation submodule:

    git clone --recursive https://github.com/chasem-dev/sms-pc-port.git
    cd sms-pc-port
    
  2. Install the prerequisites for your system: Linux, macOS, Windows.

  3. Put your disc image in rom/: one .iso, .gcm or Dolphin .ciso of GMSE01 Rev 0.

  4. Build and play:

    ./build.sh
    ./run.sh
    

    On Windows, run these in the MSYS2 MINGW64 shell, or run .\build.cmd and .\run.cmd from PowerShell.

The first build compiles about 600 game files and takes a while; later builds only rebuild what changed. Because the image is in rom/, ./build.sh also makes a standalone copy with the game's files inside (sms-standalone, or SMS.app on macOS) that runs without the image. See BUILD.md.

You can also keep the image elsewhere and pass it: ./run.sh "/path/to/Super Mario Sunshine (US).iso".

Build and run

The same two scripts work on every system:

Command What it does
./build.sh [IMAGE] builds build/<os>-<arch>/sms; with an image (argument, SMS_DISC_IMAGE, or the one in rom/) also the standalone copy
./run.sh [IMAGE] [--headless] runs that build: with the image you pass, else the standalone copy, else the image in rom/
./clean.sh [--all] [--dry-run] deletes the build output (every build/<os>-<arch>/); never deletes your disc image, and keeps the downloaded SDL2; --all deletes all of build/
SMS_ARCH=64 ./build.sh chooses the word size (Linux: 32 default or 64; macOS: 64 only; Windows: 64 default (32 legacy with MINGW32))
JOBS=2 ./build.sh limits parallel compiler jobs (default: all cores)
SMS_STANDALONE=0 ./build.sh skips the standalone copy even when an image is found

./build.sh --help, ./run.sh --help and ./clean.sh --help print the details. When both a 32-bit and a 64-bit build exist, ./run.sh runs the 32-bit one unless SMS_ARCH=64 is set.

Options

Options can be kept in settings.txt (resolution = 2, texture_packs = on, ...), or set as environment variables before the command, for example SMS_SKIP_MOVIES=1 ./run.sh; an environment variable wins over the file:

Option Effect
SMS_SKIP_MOVIES=1 skip cutscenes; keep portal animations playing
SMS_LANGUAGE=fr play in French, German (de), Spanish (es) or Italian (it) instead of English (en, the default), with that language pack installed
SMS_HEAT_HAZE=0 turn off the heat-wave shimmer that distorts the picture in sunny areas
SMS_BUTTON_PROMPTS=style the buttons shown in the game's text and on the FLUDD gauge: gamecube (the game's own, the default), xbox, playstation, steamdeck, keyboard, or auto (keyboard and mouse or the controller in use)
SMS_BUTTON_PROMPT_PAD=style with auto, how every controller's prompts look: xbox, playstation, steamdeck or gamecube (default: match the controller)
SMS_BUTTON_PROMPT_DIR=dir the prompt images, <style>.png (eight 64x64 icons in a row: A B X Y Z L R C-stick); SMS Launcher draws them from your bindings
SMS_HDR=1 HDR output on Windows while Windows HDR is on: the SDR picture is expanded to HDR and presented through a Direct3D 11 swap chain (scRGB). --display-info prints what Windows reports for each display (HDR, peak and full-frame nits, SDR content brightness, calibration profile) as JSON
SMS_HDR_PAPER_WHITE=nits how bright ordinary whites, menus and text are in HDR; auto (default) uses Windows' SDR content brightness
SMS_HDR_PEAK=nits the brightest an HDR highlight reaches; auto (default) uses the display's peak as Windows reports it, which follows a Windows HDR Calibration profile
SMS_HDR_CONTRAST=n, SMS_HDR_SATURATION=n HDR contrast (50 to 150) and saturation (0 to 200), percent; 100 leaves them as they are
SMS_HDR_HIGHLIGHTS=n 0 to 100 (default 40): how far the brightest parts climb toward the peak, in stops; 0 keeps SDR white at the paper white, 100 puts it at the peak
SMS_HDR_COPY=1 hand each frame to Direct3D through system memory instead of a texture shared with OpenGL (about 1.3 ms more per frame at 4K). The game does this by itself when the graphics driver will not share a texture; this forces it, for a driver that shares one but shows it wrong
SMS_AUDIO=0 no sound
SMS_VOLUME=n master volume, 0 to 100 (default 100)
SMS_SAVE_DIR=dir memory card folder
SMS_SAVE_STATE_DIR=dir save state folder (default: savestates beside the memory card folder)
SMS_BINDINGS=file key bindings file (default bindings.txt in this folder)
SMS_DISC_IMAGE=file disc image to use when none is passed
--headless (after the image) or SMS_HEADLESS=1 no window, for testing (Linux only)
SMS_OVERLAY=1 open the debug overlay at start
SMS_GX_SCALE=n render at n times the GameCube's resolution
SMS_ANISO=n anisotropic filtering, 2 to 16 (up to what the GPU supports), for sharper textures at glancing angles; textures whose mipmap levels are an effect (such as the sea's sparkles) keep the GameCube's level of detail
SMS_FULLSCREEN=1 borderless fullscreen at the desktop's resolution (on Windows, an undecorated normal window one row taller than the monitor, without an SDL fullscreen transition, so the driver does not promote it to a fullscreen flip that blanks the monitor); exclusive switches the display to SMS_FULLSCREEN_MODE=WxH@Hz (else the desktop's mode; on a monitor with Windows HDR on it stays borderless, since a mode switch can leave HDR's colours wrong). F11 or Alt+Enter toggles fullscreen while playing
SMS_DISPLAY=n the monitor to open on (0 is the primary one; by default, the one under the mouse)
SMS_VSYNC=1 wait for the display's refresh; adaptive shows a late frame at once instead of waiting a whole refresh
SMS_MSAA=n multisample anti-aliasing with 2, 4 or 8 samples (up to what the GPU supports)
SMS_GX_GL_THREAD=0 keep OpenGL on the game's own thread instead of a thread of its own (for troubleshooting a graphics driver)
SMS_FXAA=1 FXAA on the final picture, smoothing edges MSAA leaves (alpha-tested foliage, fences)
SMS_SHARPEN=n contrast-adaptive sharpening of the final picture, 0 to 100
SMS_GAMMA=x brightness curve: 1.0 is unchanged, above 1 is brighter (0.3 to 3)
SMS_ASPECT=stretch fill the window instead of keeping the picture's shape; integer keeps whole multiples of 640x528
SMS_PRESENT_FILTER=sharp scale the picture with crisp pixels (nearest for none at all; default bilinear, which averages when the internal resolution is above the window's; fsr upscales a lower internal resolution with AMD FSR 1, sharpened as much as SMS_SHARPEN asks; nis with NVIDIA Image Scaling, sharpened from NVIDIA's default up as SMS_SHARPEN asks)
SMS_FSR_MODE=quality with fsr or nis, render at a share of the picture's size on screen and upscale the rest: native (100%), quality (67%), balanced (59%), performance (50%) or ultraperformance (33%); it sets the internal resolution in place of SMS_GX_SCALE
SMS_WIDESCREEN=16:9 widescreen (also 21:9, 16:10): a wider view, with the HUD and menus kept 4:3 in the middle
SMS_FRAME_RATE=30, 60, or 120 gameplay frame rate: 30 (GameCube native), 60 (port default), or 120 (optional); logos, menus and movies stay at 30
SMS_WIDESCREEN_HUD=edges with widescreen, move the gameplay HUD's counters to the left edge and the water gauge to the right one

Optional mods, such as HD texture packs, go in mods/; python3 tools/mods/get.py textures downloads and installs the UHD texture pack there.

Saves go to a memory card in slot A, kept as files in ~/.local/share/sms-port/card-a on Linux and macOS ($XDG_DATA_HOME/sms-port/card-a if that is set) and in %APPDATA%\sms-port\card-a on Windows. Every other switch (debugging, tracing, graphics) is listed in docs/DEVELOPMENT.md.

Frame rate

Gameplay defaults to 60 frames a second; choose 30 for the GameCube's native rate or 120 for smoother motion in settings.txt (frame_rate = 120) or with SMS_FRAME_RATE=120 ./run.sh. The launcher offers these three choices under Settings → Gameplay → Frame rate. Game speed stays the same, and logos, menus and movies stay at 30 fps. 120 fps is available on any display, but needs sufficient CPU/GPU performance; a display running at 120 Hz or faster shows its full benefit. With display vsync enabled (vsync = on / SMS_VSYNC=1), a slower refresh rate can limit presentation, so leave vsync off to avoid that limit. Like on the GameCube, missed retraces can reduce the achieved frame rate in steps. The debug overlay (backtick) shows where each frame's time goes:

  • game: the game's own code (and the GX commands it writes).
  • GX: the renderer, split into vertices (loading GX vertices), batches (issuing draws), textures, copies (EFB copies) and peeks. waiting for the GPU is the part of it spent blocked on the GPU, or on the thread that hands the frame to the graphics driver.
  • present and swap: drawing the frame to the window and SDL_GL_SwapWindow.
  • idle: the game waiting for the next retrace, which is spare time.

If the overlay's GL line says llvmpipe, softpipe or Software, the game is rendering on the CPU and cannot hold 30 fps. On Linux this is usually the 32-bit build without the GPU driver's 32-bit libraries; build 64-bit (SMS_ARCH=64 ./build.sh) or see BUILD.md.

Controls

Controller 1 reads the keyboard and any game controller SDL recognises (A/B/X/Y, Start, right shoulder = Z, triggers = L/R, sticks, d-pad). Keyboard defaults:

GameCube adapters work too. On Windows, an adapter in Wii U mode (Nintendo WUP-028, Mayflash and other copies; USB 057e:0337) is read directly through WinUSB, so it needs its WinUSB driver (the one Dolphin installs); SMS_GC_ADAPTER=VVVV:PPPP adds another USB id and SMS_NO_GC_ADAPTER=1 turns it off. In PC/HID mode the adapter is a normal joystick for SDL. The first plugged port is controller 1.

GameCube Keys
Control stick arrow keys or WASD (hold Left Ctrl for half tilt)
C-stick I / J / K / L
A Space or X
B Shift or C
X / Y V / F
Z Z
L / R (full press) Q / E
Start Enter
D-pad 1 2 3 4 (up, down, left, right) or keypad 8 2 4 6
Debug overlay (frame rate, stats, keys) ` (backtick)
Game and movie speed x1 / x2 / x4 / x10 (overlay open) F7
Warp menu (debug overlay open) F8, or a controller's Back/Select button
Save a save state F5, or L1 + R1 (LB + RB) held together on a controller
Save states list (in the pause menu) the same: F5, or L1 + R1
Load the newest save state F6
Quit Esc

The warp menu lists every stage on the disc (Eclipse's too) and, under each, its episodes and secret courses with their names and scene files; picking one warps there straight away, as a pipe or the pause menu's Exit Area would, without the Shines that would unlock it. It warps while a stage is playing (not during a cutscene, dialogue or the pause menu); the game keeps running behind it but reads no input. Arrow keys or the d-pad (or the left stick) move, Enter or A opens a stage and warps, Esc, Backspace or B goes back; LB/RB and Page Up/Down skip a page, and the mouse works too. F8 and Back/Select open it only while the debug overlay (`) is open; otherwise they are ordinary keys and buttons, so PAD_BACK can still be bound to a game control (it then opens the menu instead while the overlay is open).

Save states

A save state is the game at one moment: in a level, F5 or L1 + R1 (LB + RB) saves it. The pause menu shows those buttons at its top right with LOAD SAVE STATE: press them there to open the list of states, newest first, with a picture of each; A loads one, Y deletes it, B goes back. F6 loads the newest without the menu. The buttons show as your keyboard or controller shows them, from the launcher's button prompt pictures (their names without the launcher). Loading a state saved by the same build of the game puts everything back as it was, Mario, enemies, the camera, the music, in place and at once. A state from another build (an update, someone else's game, another word size) cannot be put back that way; it takes you to its level and episode and puts Mario where he was, with his health, FLUDD's water and nozzle, and the progress the state had (Shines, coins, lives). The list marks those states "position". States are files (*.smsstate) in a savestates folder beside the memory card folder (~/.local/share/sms-port/savestates by default; SMS_SAVE_STATE_DIR or save_state_dir sets another); share one by sending the file. Loading a state takes you to its progress too, so saving to the memory card afterwards saves that. Saving a state does not touch the memory card. How states work, and their limits: docs/SAVE-STATES.md.

To change them, edit bindings.txt (CONTROL = KEY KEY ..., one control per line; a line replaces that control's defaults), or point SMS_BINDINGS at another file.

Controller buttons can be remapped the same way, by name: PAD_A, PAD_B, PAD_X, PAD_Y, PAD_LB, PAD_RB, PAD_LT, PAD_RT, PAD_START, PAD_BACK, PAD_DPUP … (the full list is in bindings.txt). A line's keys and buttons each replace only their own kind, so A = PAD_Y moves A to the controller's Y button and keeps Space and X; Z = PAD_RT puts Z on the right trigger. L and R stay analog when bound to a trigger.

Two keys or two buttons joined with + must be held together: the default SAVE_STATE = F5 PAD_LB+PAD_RB saves with F5, or with L1 and R1 (LB and RB) held at once. While one of such a pair is held, the game does not see the other, so holding L1 and then pressing R1 does not also press Z.

L_SOFT and R_SOFT are a light L or R press: the trigger goes part of the way, without the click, as when a GameCube trigger is pressed gently (for example, spraying FLUDD on the move with R). They have no default keys; bind them like any other control (R_SOFT = LALT PAD_RB). SMS_SOFT_TRIGGER=n (soft_trigger) sets how far, 5 to 95 percent (default 40).

SMS_CAMERA_INVERT_X=1 and SMS_CAMERA_INVERT_Y=1 invert the C-stick's camera control left/right and up/down, for keys and controllers alike (recorded .dtm movies are played as recorded). The launcher sets them from Settings → Gameplay → Invert camera X / Y (X on, Y off by default), effective on the next game launch.

SMS_FREE_CAMERA=1 keeps the camera where you point it: it no longer swings back behind Mario by itself as he runs (L still recentres it). SMS_CAMERA_SPEED=n scales how fast the C-stick turns the camera, in percent (100 is the game's own; 10 to 400). SMS_MOUSE_CAMERA=1 turns the camera with the mouse: the window captures the mouse while it has focus, F10 releases it and a click takes it back; SMS_MOUSE_SENSITIVITY=n sets its speed in percent. The invert settings apply to the mouse too.

The game ignores the keyboard and controllers while another window has focus, so a controller used in another app (or in the launcher) does not also move Mario. Anything held is released when the window loses focus; a button still held when you come back counts once you press it again. SMS_BACKGROUND_INPUT=1 (background_input) keeps input on in the background.

Controllers rumble where the game rumbles the GameCube controller: the one you last pressed or moved does, through SDL (Xbox, PlayStation, Switch and other controllers with motors), and on Windows a controller on a GameCube adapter read through WinUSB does too, when the adapter's second (power) cable is plugged in. The game's own Rumble option turns it on and off as on the console; SMS_RUMBLE=0 (rumble = off) turns it off for the port, and SMS_RUMBLE_STRENGTH=n (rumble_strength) sets its strength in percent (default 100; SDL controllers only). Rumble stops while another window has focus.

On the file-select screen, walk Mario left under a block for about half a second and press A to jump into it.

Repository layout

build.sh, run.sh      build and run, on every system
clean.sh              delete build output
*.cmd                 the same three from PowerShell or Command Prompt (Windows)
bindings.txt          keyboard bindings
rom/                  your disc image (ignored by git)
build/<os>-<arch>/    build output (ignored by git)
decomp/               the decompilation (git submodule: sms-english)
decomp-patches/       PC-only changes applied to copies of decomp sources at configure time
platform/             host replacements for the GameCube SDK: graphics, disc, audio, input, OS
src/                  entry point and compatibility headers
tools/                build helpers and developer tools
docs/                 developer documentation and reference screenshots

Documentation

  • BUILD.md: prerequisites for each system, the standalone build and macOS app, manual CMake builds, troubleshooting.
  • docs/DEVELOPMENT.md: where a fix goes (decomp, patch or platform), how the build works, the platform layer, the decomp patches, every environment variable, developer tools, performance.
  • docs/64-BIT.md: how the 64-bit build works and what is left.
  • platform/*/README.md: each platform module in detail.

The standalone build contains the whole game, so keep it to yourself: sharing it is sharing the game.

Languages

The North American disc is in English; the European release adds French, German, Spanish and Italian. A language pack holds one of those languages' text and menus, taken from the European disc, for this port to play with your North American one: dialogue, cutscene subtitles, signs, menus, the HUD, the title screen and the memory card screens. python3 tools/mods/get.py language fr installs the French pack in mods/languages/fr (de, es, it for the others), and language = fr in settings.txt (or SMS_LANGUAGE=fr) plays in it; SMS Launcher does both from its Language setting. Saves are the same in every language. The packs are made with the scripts in sms-hd-texture-extras; mods/README.md describes their layout.

HD cutscenes

The optional HD pack enhances all 21 original movies at 3× resolution and preserves their timing and original audio. The updated launcher installs the movie patches from your own disc when HD textures are enabled. See HD cutscenes for installation, conversion tools and playback checks.