# Senjin Aleste — native port A native **Linux x86-64** build of the arcade shooter *Senjin Aleste* (M2, ALL.Net P-ras Multi Ver.3 / APM3 version), made by **static recompilation** of the original Windows executable into C, plus a hand-written native system layer (SDL2, OpenGL 3.3, FreeType). No Wine, no emulator, no interpreter. It also provides a **Windows replacement for `apm_x86.dll`** so the original game runs on a normal Windows PC (free play, offline, gamepad, CRT filter) without TeknoParrot. > **Legal notice.** This repository contains **no part of the game**: no executable, no data, no generated code, no binaries > built from it. You need your own copy of the game. The build scripts translate *your* executable on *your* machine. > Senjin Aleste is © M2 / its respective owners. This project is not affiliated with or endorsed by them. > Do not open issues asking where to get the game. Version: see [`VERSION`](VERSION) and [`CHANGELOG.md`](CHANGELOG.md). ## Status - Fully playable on Linux and WSL2 (WSLg): graphics, sound, music, voices, Japanese system texts, keyboard and gamepad (with rumble). - Aime (player card) screens are skipped automatically. - Options: playfield only without bezel (F8), CRT filter (F9), 60 Hz limiter. - Windows: the original executable + this project's `apm_x86.dll` and launcher. Tested with the executable whose SHA-256 is in [`recomp/exe.sha256`](recomp/exe.sha256) (title screen "VER. 1.02"). Other builds will not match `recomp/recomp_info.json`. ## Linux / WSL2 ### 1. Build Debian / Ubuntu: ```sh sudo apt install build-essential pkg-config python3-pip libsdl2-dev libfreetype-dev libfontconfig-dev libgl-dev pip install capstone pefile # or: sudo apt install python3-capstone python3-pefile ./build.sh /path/to/game/senxin_aleste_apm3.exe ``` This generates ~30 MB of C in `recomp/gen/` (never commit or share it) and builds `out/senjin_aleste`. The first build takes a few minutes; later builds only recompile the native layer. ### 2. Play ```sh ./play.sh deps # once: SDL2, ffmpeg, Mesa, a Japanese font (sudo) ./play.sh /path/to/game/folder # the folder that contains senxin_aleste_apm3.exe and windata/ ``` - **WSL2**: the game runs on your Windows GPU through Mesa d3d12 (`./play.sh info` shows the renderer). Games stored on a Windows drive (`/mnt/c/...`) are copied once to `~/.local/share/senjin-aleste/game` because Windows drives are slow from WSL2. WSL2 cannot see USB gamepads: build the Windows tools (below) and `play.sh` starts `out/windows/aleste_pad.exe`, a small XInput relay. - **Linux**: gamepads are read directly through SDL2, no relay needed. Every connected pad works at once. Pads SDL knows (Xbox, PlayStation, Switch Pro, Steam Deck / Steam Input...) use the Xbox layout by position; extra mappings can go in `gamecontrollerdb.txt` in the game folder (or `SDL_GAMECONTROLLERCONFIG`). Other joysticks (USB arcade sticks and encoders) use a generic layout: hat or first two axes = D-pad, buttons 1-8 = A B X Y LB RB Back Start. - **Steam Deck**: `./play.sh deck /path/to/game/folder` builds `out/deck/senjin-aleste-deck.tar` (game binary, static ffmpeg, Japanese font, your game files, Deck settings). Copy it to the Deck, extract it and add `aleste-deck.sh` to Steam as a non-Steam game: step by step in [STEAMDECK.md](STEAMDECK.md). - `./play.sh
]` sections of `launcher.ini`.
Known limitation of `nobezel=1` and `tate=1`: texts drawn outside the playfield ("PRESS START BUTTON" in attract mode, system messages at the bottom) are hidden.
## Troubleshooting
| Variable | Effect |
|---|---|
| `SA_FPS=n` | frame limiter (default 60, 0 = off) |
| `SA_PERF=1` | time per frame in the log |
| `SA_NODRAW=1` | run without drawing (measures game logic) |
| `SA_AUDIO_LOG=1` | audio mixer log |
| `SA_XINPUT=1` | let the game read XInput itself (normally off: inputs go through the APM3 layer) |
| `SA_PADNET=port` | WSL2 gamepad relay port (default 47011) |
| `SA_FONT=path` | force a font file for Japanese texts |
| `SA_KEYTEST=1` | F1-F12 press raw arcade inputs 3-14; arcade inputs traced in the log |
| `SA_VPAD=1` / `2` | test: SDL virtual gamepad / generic joystick driven by the `SA_PADNET` relay |
`kill -USR1 ` prints a report of the Windows APIs called so far. Unhandled instructions or unknown indirect jumps are logged with their original address.
## How it works
```
senxin_aleste_apm3.exe ──x86recomp.py──▶ recomp/gen/*.c (one C function per x86 function)
│
native/ (KERNEL32, USER32, D3D9→OpenGL, XAudio2, GDI, DirectInput, APM3) ─┤──gcc──▶ out/senjin_aleste
kit/recomp_x86/x86rt.c (runtime helpers) ───────────────────────────────┘
```
- The game keeps its original 32-bit addresses inside a reserved 4 GB block; the PE image is loaded at 0x400000, imports point to native functions.
- CPU state (registers, flags, XMM, x87) is per-thread C state; indirect calls go through an address -> function table.
- Details: [`docs/recompilation.md`](docs/recompilation.md), [`docs/engine-map.md`](docs/engine-map.md), [`kit/recomp_x86/README.md`](kit/recomp_x86/README.md).
## Layout
| Path | Content |
|---|---|
| `native/` | native system layer (Linux) |
| `recomp/` | `recomp_info.json` (function boundaries / jump tables exported from Ghidra — addresses only), `gen.sh`, expected exe hash |
| `kit/recomp_x86/` | the x86 -> C generator and its runtime, Ghidra export script |
| `kit/crt/`, `kit/launcher/`, `kit/version/` | CRT filter, common launcher, version stamping |
| `src/apm3/` | Windows `apm_x86.dll` replacement and Direct3D 9 overlay |
| `src/pad/` | `aleste_pad.exe`, WSL2 gamepad relay |
| `tools/ghidra/` | analysis scripts |
| `docs/` | documentation and analysis data (addresses only) |
Source comments and some log messages are still in French.
## License
MIT for the code in this repository (see [`LICENSE`](LICENSE)). The game itself is not covered.