Skip to content

Feature/retro console emulation - #622

Open
maxjivi05 wants to merge 6 commits into
WinNative-Emu:mainfrom
maxjivi05:feature/retro-console-emulation
Open

Feature/retro console emulation#622
maxjivi05 wants to merge 6 commits into
WinNative-Emu:mainfrom
maxjivi05:feature/retro-console-emulation

Conversation

@maxjivi05

@maxjivi05 maxjivi05 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Adds retro console support alongside the existing Wine/PC library. Retro games sit in the same Library and launch like PC games, but run on a libretro backend instead of Wine — or, for PS2 and GameCube/Wii, on a full emulator in its own process.

No emulator core ships in the APK. Every core is built from its own fork under WinNative-Emu, packed into a single archive by WinNative-Emu/Retro-Consoles, and downloaded on demand from Settings › Retro.

Consoles

System Backend Process
NES FCEUmm in-app
SNES Snes9x in-app
Game Boy / Color Gambatte in-app
Game Boy Advance mGBA (gpSP for link-cable multiplayer) in-app
Genesis / Master System / Game Gear Genesis Plus GX in-app
Nintendo 64 Mupen64Plus-Next (GLES3) in-app
PlayStation Beetle PSX in-app
PlayStation 2 ARMSX2 :ps2
GameCube / Wii Dolphin (standalone, Vulkan) :gc

Core delivery

The app used to carry ~150 MB of core binaries and emulator data in git. That is gone.

  • Each of the 10 emulator forks builds its own arm64-v8a artifact and publishes it to a rolling latest release.
  • Retro-Consoles pulls every core plus the Dolphin Sys tree and ARMSX2 runtime assets into one retro-consoles.tzst (currently 38.5 MB, 11 cores).
  • The app downloads it, verifies the SHA-256, extracts to a staging tree and swaps it in atomically — an interrupted install can never leave a half-installed core set behind.
  • Retro launches are gated on the bundle being present, with a message pointing at Settings › Retro rather than a late failure.

Updates

bundle-info.json is published beside the archive carrying the tag, build date, checksum and size. A copy of the installed one is the on-disk marker, so "is there an update" is an exact checksum comparison rather than a guess from timestamps. Settings › Retro checks once when the screen opens (a 193-byte fetch) and the row reads Installed — build 2026-07-28 until something newer exists, at which point it becomes Update available — build … (36 MB) and the button changes from Check for updates to Update console cores. Nothing downloads without a tap.

Release train

Every core fork rebuilds Friday 17:00 ET, syncing its upstream parent first; the bundle is packed at 18:00 ET. Both compare their output against what is already published and release nothing when it is byte-identical, so a week with no upstream change costs users no download. This required making the archive reproducible (tar --sort=name --mtime=@0 --owner=0 --group=0 --numeric-owner, single-threaded zstd, no run-stamped files inside) — verified by two consecutive runs producing identical archives and skipping the release.

Also in this branch

  • RetroAchievements via rcheevos — login, achievement lists, in-game unlock toasts. Softcore only; hardcore is hidden because it needs per-client registration with RA.
  • Core options — 347 settings generated from each core's own source, grouped into Display / Sound / Performance / Controls / System tabs, exposed both as per-console defaults and per-game overrides.
  • Touch controls with editable layouts, per-game profiles and 3D-styled buttons.
  • Netplay for the libretro cores and for Dolphin, plus GBA link-cable multiplayer via gpSP.
  • Save states, cloud save sync, and a draggable performance HUD.
  • 22 locales fully translated.

Notes for review

  • libdolphin_libretro_android.so is the one core still in the APK: it is the legacy libretro GameCube path behind the wn.gc.embedded toggle, and no fork builds it. Everything else resolves from the bundle only — there are deliberately no APK fallbacks, so a missing bundle fails loudly instead of silently degrading.
  • The four adrenotools hook libraries Dolphin needs are dlopened by name from the APK's own library directory and are intentionally absent from the bundle.
  • Vendored third-party trees (libretrodroid/src/main/cpp, org.libsdl, dolphin/vendored, app/src/main/cpp) are carried as-is.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@maxjivi05
maxjivi05 force-pushed the feature/retro-console-emulation branch 3 times, most recently from f08b60f to 2f126b7 Compare July 23, 2026 17:10
Adds retro console support alongside the existing Wine/PC library: NES, SNES,
Game Boy / Color / Advance, Genesis, Master System, Game Gear, N64, PlayStation,
PlayStation 2 and GameCube / Wii. Retro games live in the same Library and
launch like PC games, but run on a libretro backend, on ARMSX2 in a separate
:ps2 process, or on an embedded standalone Dolphin in :gc.

No core ships in the APK. Each emulator is built from its own fork under the
WinNative-Emu org, WinNative-Emu/Retro-Consoles packs every core plus the
Dolphin and ARMSX2 runtime data into one retro-consoles.tzst, and the app
downloads and SHA-256-verifies it from Settings > Retro. The forks rebuild every
Friday at 17:00 ET and the bundle is packed at 18:00; both compare against what
is already published and release nothing when the output is byte-identical, so a
quiet week costs users no download. bundle-info.json carries the tag, build date,
checksum and size; the installed copy is the marker file, so the app only offers
an update when the published checksum actually differs.

Also included:
- RetroAchievements via rcheevos, softcore only (hardcore needs per-client
  registration and is hidden until then)
- Per-console core options generated from each core's own source, grouped into
  Display / Sound / Performance / Controls / System tabs
- Touch controls, netplay for the libretro cores and Dolphin, save states,
  cloud save sync and a performance HUD
- 22 locales translated
@maxjivi05
maxjivi05 force-pushed the feature/retro-console-emulation branch from 6fea9a9 to 02b7412 Compare July 28, 2026 15:09
…ease"

/releases/latest/download resolves to whichever release was published most
recently, which is the immutable bundle-<date>-<sha> tag, not the rolling
"latest" tag the workflow maintains. Both carry the same assets today, so this
worked by luck; a run that created the immutable tag and then failed before
updating latest would have pointed the app at the wrong archive.
/releases/download/latest names the tag itself.
Turning the HUD off in a game changed a single global preference
(retro_def_hud_global, which ignored the system id it was passed), so it went off
for every game on every console. The shortcut settings screen edited that same
global value while presenting it as a per-game setting.

The HUD now follows the pattern every other setting already used: the shortcut
extra is the value, the console default is only the fallback when the shortcut
has never been set. Both the in-game menu and the shortcut settings screen read
and write that one place, on all three launch paths (libretro, embedded Dolphin,
and PS2).

The PS2 process had no shortcut reference at all, so it also gained the shortcut
path and container id at launch, and queues writes until the shortcut loads.

Auditing the rest of the menu turned up the same bug twice more, in the PS2
overlay only: on-screen controls and adaptive sticks wrote the console default
where libretro and Dolphin persist them per game. Both now write the shortcut,
and the PS2 launch seeds its cross-process prefs from the shortcut rather than
from whatever the last game left behind.

Settings > Retro still edits the console defaults, which is its job; the two HUD
call sites now say explicitly which store they write. HUD element selection and
style stay global.
Adds a second way to run Pokémon Red/Blue/Yellow: gen1recomp, a Lua
reimplementation of the games, with the Dramatic Shape voxel mod drawing the
overworld as a 3D diorama. It is hosted the way Dolphin is -- in WinNative's
own process, with WinNative keeping the menus, the settings and the controls
-- so the engine's own launcher, options menu and touch pad never appear.

Offered per game, above Play and on the Graphics pane, and only for a ROM
whose SHA-1 matches a supported title with the engine present in the bundle.
Everything else launches on the standard core exactly as before.

The menu is the real Retro drawer, the same composable the GB/GBC/GBA paths
use. It turned out never to have been tied to libretro: RetroMenuController
takes callbacks that return rows, so these rows come from the engine
instead. They are the engine's OWN option rows, read over a file bridge, so
the mod's settings appear without WinNative knowing anything about them and
stepping a row runs the engine's own handler with its side effects. An
earlier attempt drove the engine by injecting keystrokes; that could never
read a value back, so every switch was a guess, and it deadlocked SDL.

Notable pieces:

  Gen1EngineActivity  hosts the engine. SDLActivity extends plain Activity,
                      so this supplies the lifecycle owners Compose needs --
                      on the window's decor view, since Compose resolves them
                      from the window root, not from the ComposeView.
  Gen1EngineBridge    the host half of the control channel.
  Gen1ModInstaller    unpacks the mod from the bundle. It must be the app
                      that writes those files: files placed in its external
                      storage by another uid are listed but cannot be opened
                      through Android's FUSE layer, which made the engine
                      report zero mods installed with no error.
  RetroShortcuts      usesEmbeddedLauncher, now the single answer to "does
                      this shortcut need a non-libretro launcher". Two
                      callers each had their own list, and the one in
                      UnifiedActivityLaunch knew about PS2 and Dolphin but
                      not this, so 3D-enabled games silently opened on the
                      standard core.
  RetroDrawerMenu     a Stepper row, for a setting whose value set the host
                      does not know. Choice cannot express that.
  app/src/main/engine  SDL2 and love-android glue, vendored under
                      org.love2d.sdl. ARMSX2 ships org.libsdl.app from a
                      different SDL version and only one copy survives dex
                      merge; the engine build renames its half to match.

The engine surface is sized to a whole multiple of 160x144 rather than to
whatever fits, because the engine scales by an integer factor and centres the
remainder -- so an exact-fit rectangle just moved the black border inside the
surface, leaving the picture floating below a band with its lower edge behind
the buttons.
@maxjivi05
maxjivi05 force-pushed the feature/retro-console-emulation branch from 58821f8 to ca42263 Compare July 31, 2026 02:43
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.

1 participant