sfa3max-decomp

sfa3max-decomp is a decompilation of Street Fighter Alpha 3 MAX for PC, featuring moddable assets and up to three local players.

README

Street Fighter Alpha 3 MAX: Decomp

A source decompilation of Street Fighter Alpha 3 MAX (PSP): the game rewritten, function by function, as readable C, running natively on PC, with the game's assets extracted into formats anyone can edit. It is based on my earlier static recompilation of the game, and keeps the extensions that added: up to three local players, widescreen, everything unlocked and the new options.

The US release (ULUS-10062) comes first; the Japanese Street Fighter Zero 3 Double Upper (ULJM-05082) follows once the US build is complete.

No game data is in this repository: you build it from your own copy of the game.

Why I'm doing this

I spent my teenage years messing around with Game Genies and Action Replays and sending codes in to gaming magazines; some of them even got published. It was one of the many things that got me into gaming, and later into computers.

I've worked as a developer for many years, and like most people in the profession I'm expected to stay curious and keep skilling up. Companies are asking us to look at AI tooling more and more, so when I saw the hype train around static recomps (and the stigma that comes with it), I was intrigued by what I could do, and whether I could learn some C along the way (honestly, it's not my main language).

Why a decomp, after the recomp?

The recomp got the game running natively with the features I wanted, but its code is the PSP program translated instruction by instruction: it works, and it's very hard to read or change. Every new feature means finding the right spot in machine-translated code and hooking around it.

The decomp is the next step:

  • Readable code. Game logic as structured C (loops, structs, enums, switch statements) that people can understand, fix and extend, rather than registers and jumps.
  • The same game. Every function is checked against the original, frame by frame, so the physics, timing and state machines stay exactly as Capcom made them.
  • Moddable assets. Sprites, stages, UI, music and sounds extracted into standard formats (PNG, WAV / OGG) in an assets/ folder, loaded from there instead of baked-in offsets.
  • Other systems. Game logic kept apart from the PC side (graphics, sound, input), so Linux and Steam Deck builds become possible.

The goal is for the translated code the recomp started from to disappear entirely, one function at a time, while every extension keeps working.

Why the Street Fighter Alpha series?

I remember going to Hong Kong in the 90s and seeing Street Fighter Zero in the arcades there. It blew my mind how much of a step up it was from Street Fighter II. When the Japanese PlayStation version of Zero came out, my brother and I played hours of Dramatic Battle, and it's a mode we still play to this day. So it holds a big place in my heart.

Why the PSP MAX version?

Like most retro games and their re-releases, every version of Street Fighter Alpha 3 has something extra that makes it good, and then some limitation that stops it from being truly great. I've played all of them and own most, and in my opinion the PSP version felt the place to start. The Saturn version was close second though! For a breakdown of version difference see docs/VERSION_DIFFERENCE.md.

Why I picked it
  • The modes and roster are comprehensive, and I think I can lean into extending it well.
  • Hooks called be intercepted and allow for same-screen multiplayer
  • Widescreen (sort of). It messes up the pixel ratio, but there are patches around that help. This project uses the SFA3MAX PSP widescreen patch by Rickow currently while I figure that out.
Why I wish I hadn't...
  • PSP player and button support. It is one player = one device
  • Memory sticks are stupid and added the menu confirmation nightmare.
  • No L2 and R2 buttons.
  • The menus, modes and character select screens are inconsistent and seem to have different hooks (all over the place).

What is the current status?

Phases 2 and 3: the system layer and the game (now). The game builds and plays from day one: every function not decompiled yet is translated from the PSP program at build time, and hand-written functions in src/core/ take their place one at a time. A parity test runs the game both ways and checks every frame is identical.

Progress

How much of the PSP program is decompiled into hand-written C (python tools/progress.py --by-region). Updated by python tools/progress.py --update-docs with every PR that decompiles functions; a block on the bar is a full tenth. Every decompiled function is verified by the tests before it is merged.

Functions                                [░░░░░░░░░░]   2.78%  414 / 14,881 functions
Instructions                             [░░░░░░░░░░]   4.80%  23,255 / 484,213 instructions

By area (instructions):
  game (modes, menus, fighters, battle)  [█░░░░░░░░░]  10.80%  22,027 / 203,929
  wireless (ad-hoc) VS                   [░░░░░░░░░░]   0.00%  0 / 3,721
  game (to be mapped)                    [░░░░░░░░░░]   0.05%  134 / 257,012
  system: save data, graphics, music     [░░░░░░░░░░]   0.00%  0 / 2,574
  system: C library, sound, OS glue      [░░░░░░░░░░]   6.44%  1,094 / 16,977
PartState
DecompiledFunctions: the C library's string, memory and number routines, the heap (malloc / free / memalign), the controller read, the whole loader (files, the .pac archive loader and the background loader thread), the task system that runs the game (the main thread, the scheduler, the boot screens, screen fades, the title and its attract mode), the whole MODE MENU, the fight's loop, set-up and most of its screens, the object lists, the end of every frame, the sprite and object drawing and the start of the character select screen; every one verified by the tests. python tools/progress.py
Runtimefrom the static recomp: threads, files, timing, saves, the PSP's OS functions
GraphicsGPU renderer (OpenGL 3.3) up to 8× the PSP's resolution; software renderer as reference
Soundmusic (ATRAC3+) and effects / voices (SAS, with its reverb)
Extensionsall of the recomp's, as hooks in src/extensions/ (to become native code as their parts are decompiled)
Assetsall 313 .pac archives unpacked into assets/us/, by what they hold (characters/00_ryu/fighter/, stages/0c_dan/, screens/title/; assets/LAYOUT.md): 845 textures (indexed ones in their own palette's colours) and 148 palettes as PNG, text as TXT, everything else raw. The game loads them from there: paint over a PNG or replace a raw file and it shows up, no repacking (docs/ASSET_LOADING.md). Music copied out (decoding to come)
Parity testsboot to character select, the attract mode, an Arcade fight, the stick in menus, a misbehaving disc: identical frame by frame; plus a differential test on random inputs, an exact round trip of every archive, and loading from assets/ (unedited: identical to the disc; a changed texture and a larger entry arrive as they should)
Japanese versiondisc verified and extracted; not buildable yet

The full plan as a checklist (what's done, what's next, and the extensions to move into native code): docs/ROADMAP.md.

Prerequisites

  • Windows 10 (1803 or later) or 11 (x64), Linux (x64) or macOS 11 or later (Apple Silicon)
  • Your own Street Fighter Alpha 3 MAX PSP disc image (ISO), US release ULUS-10062
  • An internet connection for the first build

Building

No game is included: you build it from your own disc.

The easy way: download the zip for your system from the latest release (or the Nightly pre-release for the newest code, untested and unsupported) (...-windows-x64.zip, -linux-x64.zip or -macos-arm64.zip), unzip it and open sfa3max-launcher (on a Mac, Street Fighter Alpha 3 MAX Launcher.app, native on Apple silicon, macOS 11 or later). Choose your ISO with Browse... and press Run. The launcher comes prebuilt and builds the game from your disc on your machine. Linux and macOS need the tools in the table first.

Or from a clone of this repository (or the release's Source code (zip)): copy your ISO into imports/psp/ (any file name: the right disc is found by its checksum), then:

SystemOnceBuild and play
Windowsnothing: the build tools are downloaded into .tools\ the first timedouble-click create-launcher.exe (a progress bar, then the launcher opens; press Run), or build.cmd --run
Linuxsudo apt install cmake ninja-build clang python3 and SDL's libraries (list)./create-launcher.sh, or ./build.sh --run
macOSxcode-select --install, then brew install cmake ninja python./create-launcher.sh, or ./build.sh --run

create-launcher also puts a shortcut to the launcher in build-shortcut/, for next time. If it fails, try Clean and try again (or --clean with any of these scripts: it starts from nothing and keeps your saves), and if it still fails, attach work/create-launcher.log to your report.

create-launcher.exe isn't signed. Windows may stop it the first time with "Windows protected your PC" (choose More info, then Run anyway), and some antivirus programs flag small unsigned programs that start hidden processes and download tools, which is what it does. It is built only from tools/create-launcher/, and CI rebuilds it and fails if the committed file is any different; its SHA-256 is in docs/DEPENDENCIES.md, with every download the build uses. If you'd rather not run it, use the command line instead: double-click launcher.cmd, or run build.cmd --run. They do the same, in a command window.

The launcher is a small window for all of it: your ISO (checked, with its region's flag), the build's options as checkboxes, full screen and the log level, and one button, Run (or Build, with "Run after building" unchecked), with the build's and the game's output in a console underneath (details).

The first build extracts and checks your disc, translates the parts not decompiled yet and compiles (a few minutes). Playing after that: build/sfa3max --work work (build\sfa3max.exe --work work on Windows). Building again after an update does only what changed.

Every option, the presets and VS Code, and how to work on the code: docs/BUILDING.md.

Playing

The controls, modes and options (including the extensions):

KeyboardPSPGamepad
Arrow keysD-padD-pad or left stick
Z / X / A / SCross / Circle / Square / TriangleSouth / East / West / North
Q / WL / RShoulders
E / RL2 / R2 (added)Triggers
Enter / BackspaceStart / SelectStart / Back
F2Back to the MODE MENU at once, without saving (keyboard only)
F11 or Alt+EnterFull screen on / off (the game starts full screen; --windowed, or untick Full screen in the launcher, for a window)
Alt+F4 (Windows), Cmd+Q (macOS), Ctrl+Q (Linux), or the window's close buttonQuit (as any program on your system; Esc no longer quits)
  • Players, joining in and the network modes on one PC: docs/PLAYERS.md
  • Controllers and pad icons: docs/CONTROLLERS.md; buttons: docs/PLAYER_CONFIG.md
  • VSYNC and FRAME TIMING (AUTO, the default, picks SMOOTH on a 60, 120, 240 Hz ... screen and ORIGINAL, the PSP's 59.94 Hz, with VRR or other rates; the MODE MENU shows which you got): docs/DISPLAY.md
  • Saves and settings (saves/sfa3max.cfg, saves/sfa3max.dat; files from earlier builds, sfa3mr.cfg / sfa3mr.dat, are renamed on first start): docs/SAVES.md
  • Hidden extras (all unlocked): hold L + R while confirming Dramatic Battle, Variable Battle, R.Dramatic Battle or Final Battle on the MODE MENU for its alternative version; hold SELECT while choosing Akuma (Shin Akuma), M. Bison (Final Bison) or Balrog's second slot.
  • Without the extensions, as the PSP program alone (its own menus and saves, one pad): build/sfa3max --work work --no-extensions, or build that way with build.cmd --no-extensions / ./build.sh --no-extensions: docs/BUILDING.md

Layout

PathWhat
src/core/the decompiled game: hand-written C replacing translated functions (docs/DECOMPILING.md)
src/platform/the PC side: memory, threads, files, graphics, sound, input, the PSP's OS functions
src/launcher/the launcher: ISO, options, Run / Build and the console (SDL3 + Dear ImGui; no game code)
src/extensions/the extensions from the static recomp (EX. SETTING, PLAYER CONFIG, join-in, widescreen, saves, ...)
tools/extract_assets.py, pac.py (archives), progress.py, show_func.py; recomp/ the program analysis and translator; data/hooks.txt
tests/parity.py and its scenarios
assets/extracted assets (git-ignored; assets/README.md), except extensions/: new art, such as WIDE FORCED's stage edges (stage extensions); the layout's rules: assets/LAYOUT.md
third_party/ATRAC3/ATRAC3+ decoder from PPSSPP / FFmpeg (LGPL 2.1+), libkirk, Dear ImGui (MIT, the launcher): CREDITS.md
docs/building, reporting problems, architecture, decompiling, archives, loading from assets, stages, stage extensions, widescreen, display and frame timing, roadmap, decisions, program map, known issues, other versions, lessons, mistakes, concerns

Contributing

Issues and pull requests are welcome: see CONTRIBUTING.md.

Found a problem? Click the bug icon in the launcher's top right corner: it opens the bug report form with the version, your system and settings filled in; then attach work/sfa3max.log. What to include, and how to get a useful log: docs/REPORTING_ISSUES.md.

Credits

The projects that inspired this one, others working on Street Fighter Alpha 3, and the code and tools it's built with: CREDITS.md.

Licence

The project's own code is licensed under the GNU General Public License v3.0 or later (LICENSE). It covers the tools, runtime, decompiled code and documentation only and grants nothing over the game itself.

Legal

You must own the game. Disc images, extracted files, assets and generated code are never committed. Not affiliated with Capcom. Street Fighter is a trademark of Capcom Co., Ltd.