Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ features:
<span>spruce</span>
<em class="supported-platforms__tag">experimental</em>
</div>
<div class="supported-platforms__item">
<span>Allium</span>
<em class="supported-platforms__tag">experimental</em>
</div>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## What is RAOfflineProxy?

RAOfflineProxy is a local proxy that acts between supported emulators and [RetroAchievements](https://retroachievements.org/) (RA). It currently supports RetroArch, Dolphin, PPSSPP, ARMSX2, WatermelonDS, and Flycast on **Android**, and **KNULLI**, **Onion**, **muOS**, and **ROCKNIX** for Linux.
RAOfflineProxy is a local proxy that acts between supported emulators and [RetroAchievements](https://retroachievements.org/) (RA). It currently supports RetroArch, Dolphin, PPSSPP, ARMSX2, WatermelonDS, and Flycast on **Android**, and **KNULLI**, **Onion**, **muOS**, **ROCKNIX**, **spruce**, and **Allium** for Linux.

Their achievement systems talk directly to RetroAchievements over the internet. This works great online, but the moment your connection drops, achievements stop unlocking and games may fail to load their achievement lists at all.

Expand Down
10 changes: 10 additions & 0 deletions docs/linux-support/cfg-patching.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ spruce launches RetroArch with its own per-device config rather than the usual o

spruce rewrites the account and achievement keys in this file on every game launch from its own RetroAchievements settings, so starting the proxy also switches spruce's achievements mode to `Softcore`. Stopping the proxy restores whatever it was before.

== Allium

Allium launches stock RetroArch directly, so the usual config is the one that gets patched:

```text
/RetroArch/.retroarch/retroarch.cfg
```

Allium has no RetroAchievements settings of its own, so nothing rewrites these keys behind the proxy: RetroArch's own achievements login is the single source of your account details.

:::

## What Gets Patched
Expand Down
9 changes: 8 additions & 1 deletion docs/linux-support/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The Linux version is for handheld Linux devices where you want the same basic of
- Keep earning casual achievements while offline
- Let queued awards sync later when you reconnect

Use the `KNULLI`, `Onion`, `muOS`, `ROCKNIX`, and `spruce` tabs throughout the Linux section to switch target-specific instructions.
Use the `KNULLI`, `Onion`, `muOS`, `ROCKNIX`, `spruce`, and `Allium` tabs throughout the Linux section to switch target-specific instructions.

## Supported Targets

Expand All @@ -20,6 +20,7 @@ Use the `KNULLI`, `Onion`, `muOS`, `ROCKNIX`, and `spruce` tabs throughout the L
- muOS
- ROCKNIX
- spruce (experimental)
- Allium (experimental)

## Specifics

Expand Down Expand Up @@ -55,6 +56,12 @@ spruce support is experimental. It is currently compatible with [spruce 4.3.x](h

The bundled Python runtime and SDL libraries are 32-bit ARM builds, which covers spruce's 32-bit devices: the Miyoo Mini family and the A30. spruce's other devices (TrimUI, Anbernic, Miyoo Flip, GKD Pixel 2, MagicX Zero 28) are 64-bit and would need an aarch64 build, which this bundle does not ship.

== Allium

Allium support is experimental. It is currently compatible with [Allium v1.0.1](https://github.com/goweiwen/Allium/releases), tested on a Miyoo Mini Plus.

Allium is a Miyoo-only launcher, so this target covers exactly the devices Allium itself runs on: the Miyoo Mini, Mini Plus and Mini Flip.

:::

## Important Notes
Expand Down
24 changes: 24 additions & 0 deletions docs/linux-support/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ Before using `RAOfflineProxy` on Linux:
> Settings -> Additional Settings -> RetroAchievements Settings
- Make sure the system clock is correct so award timestamps are accurate

== Allium

- Enter your RetroAchievements account details in RetroArch<br>
> Allium launches RetroArch directly, so its own achievements login is what RAOfflineProxy reads.
- Make sure the system clock is correct so award timestamps are accurate<br>
> Settings -> Wi-Fi -> enable NTP

:::

::: warning Emulator configs are patched automatically
Expand Down Expand Up @@ -144,6 +151,23 @@ RAOfflineProxy patches the emulator configs it needs in order to redirect RetroA
4. Start the proxy while online
5. Launch a game once so its data is cached

== Allium

> Allium support is currently experimental.
>
> Tested on a Miyoo Mini Plus running [Allium v1.0.1](https://github.com/goweiwen/Allium/releases). Allium runs only on the Miyoo Mini, Mini Plus and Mini Flip, and this bundle covers all of them.

1. Download the latest `RAOfflineProxy-Allium-*.zip` from [GitHub Releases](https://github.com/misantronic/RAOfflineProxy/releases)
2. Extract it over the root of your SD card so the app lands in:

```text
/Apps/RAOfflineProxy.pak/
```

3. Launch **RAOfflineProxy** from Allium's Apps section
4. Start the proxy while online
5. Launch a game once so its data is cached

:::

See [Caching Games](/linux-support/caching-games) for more detail.
Expand Down
22 changes: 22 additions & 0 deletions docs/linux-support/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ That block calls the app's headless launcher:
A spruce update replaces `/.tmp_update` and removes the block. The app reinstalls it every time you open RAOfflineProxy, so autostart repairs itself after a spruce update.
:::

== Allium

Allium autostart is available from the app menu.

Allium has no drop-in startup folder either, so RAOfflineProxy adds a small guarded block to Allium's own boot script:

```text
/.tmp_update/updater
```

That block calls the app's headless launcher in the background, so Allium's own startup is never held up:

```text
/Apps/RAOfflineProxy.pak/autostart-launch.sh
```

It is also skipped entirely while an Allium firmware update is pending, so the proxy never starts up in the middle of an update.

::: tip Reinstalled automatically
An Allium update rewrites `/.tmp_update` and removes the block. The app reinstalls it every time you open RAOfflineProxy, so autostart repairs itself after an Allium update.
:::

:::

## Start / Stop Behavior
Expand Down
1 change: 1 addition & 0 deletions docs/platforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ This page tracks which emulators and Linux handheld platforms `RAOfflineProxy` c
| <img class="platforms-table__logo" src="/muos.png" alt="muOS logo"> | **muOS** | ✅ RetroArch Supported |
| <img class="platforms-table__logo platforms-table__logo--rounded" src="/rocknix.png" alt="ROCKNIX logo"> | **ROCKNIX** | ✅ RetroArch, PPSSPP Supported |
| <img class="platforms-table__logo platforms-table__logo--rounded" src="/spruce.png" alt="spruce logo"> | **spruce** | 🧪 RetroArch Supported (experimental) |
| | **Allium** | 🧪 RetroArch Supported (experimental) |
| <img class="platforms-table__logo platforms-table__logo--rounded" src="/darkos.png" alt="dArkOS logo"> | **dArkOS** | 🔜 Planned, [pending release](https://github.com/misantronic/RAOfflineProxy/pull/47) |
1 change: 1 addition & 0 deletions linux/allium/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/dist/
107 changes: 107 additions & 0 deletions linux/allium/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# RAOfflineProxy — Allium

[Allium](https://github.com/goweiwen/Allium) bundle, derived from the Onion one. Support is
**experimental**.

Allium runs on the same Miyoo Mini armv7 hardware as Onion and spruce (same kernel, same
`/config/lib` MI SDK, same `.tmp_update` boot chain), so this package reuses Onion's CPython
runtime, its pygame + `Mini` SDL2 vendor libraries and its armv7 `libraproxy_rchash.so`.

## What differs from Onion

| | Onion | Allium |
| --- | --- | --- |
| App layout | `/mnt/SDCARD/App/RAOfflineProxy/` | `/mnt/SDCARD/Apps/RAOfflineProxy.pak/` |
| RetroArch config | `/mnt/SDCARD/RetroArch/.retroarch/retroarch.cfg` | same |
| RA credentials | the RetroArch config | same (Allium launches stock RetroArch, whose own achievements login writes there directly) |
| Default proxy port | 8080 | 8080 (Allium's own HTTP/FTP/telnet toggles use ports 80/21/23) |
| Autostart | drop-in `/mnt/SDCARD/.tmp_update/startup/raofflineproxy.sh` | prepended block in `.tmp_update/updater` |
| Version gate | requires Onion v4.4.0+ | none |

Apps on Allium are `.pak` directories carrying their own `config.json`
(`{"label", "icon", "launch", "description"}`); there is no shared `App/` tree to install
into. `alliumd` runs the pak's `launch` script with the pak directory as the working
directory.

## Autostart

Allium has no drop-in boot directory either: `.tmp_update/updater` is the entire boot entry
point (it execs `alliumd` directly and only reaches the reboot loop after that returns), the
same shape spruce's boot script has on this hardware — in fact it is the literal same file
path. `install_allium_boot_hook()` therefore prepends a sentinel-guarded block straight
after the shebang, exactly like spruce's `install_spruce_boot_hook()`, and the dispatch in
`platform.py` is keyed off `running_on_allium()` rather than path equality alone, since the
two boot script constants collide by value on real hardware (they're never true on the same
device, but the guard makes that explicit instead of accidental).

The updater is regenerated by every Allium update, while `Apps/RAOfflineProxy.pak` is not,
so `launch.sh` reinstalls the hook on each app launch — the same self-repair pattern spruce
and ROCKNIX need. Concretely: `.allium/scripts/ota-update.sh` extracts the release with
`miniunz -x -o` over `/mnt/SDCARD`, so any file the archive carries — `.tmp_update/updater`
included — is overwritten. Autostart therefore stays dead from an OTA update until the app
is next opened, which is the same gap spruce has.

The hook also skips autostart entirely while `/mnt/SDCARD/allium-ota.zip` is present. It
has to: the block sits above the updater's own OTA check, and `ota-update.sh` extracts the
whole release over the card and then forces a reboot, so an unguarded hook would have the
service opening its SQLite database on that card mid-extract and seconds before the reboot.
The guard tests the same path Allium's updater does, and a test pins the two together so a
rename can't silently disable it.

### Free space

`ota-update.sh` refuses to run with less than 300MB free on the card. This bundle installs
~129MB, so on a nearly-full card installing it can be what pushes Allium below its own
update threshold. Not a problem on a roomy card, but worth knowing before blaming the OTA.

## Timezone

`alliumd` exports `TZ` from `/mnt/SDCARD/.allium/state/timezone` itself, but only partway
through `.tmp_update/updater` — after our boot hook, which is prepended right after the
shebang so it survives a dispatch that never returns. A backgrounded autostart process would
otherwise inherit an empty `TZ` and stamp every award timestamp in UTC.
`resolve_allium_timezone()` in `common.sh` reads that same file directly and exports it
verbatim (matching how the updater itself applies the value) before starting the backend.
It never overrides a `TZ` that is already set.

## Credentials

Unlike spruce, Allium does not run its own settings UI in front of RetroArch: the
`RetroArch.pak` entry execs the stock `retroarch` binary directly, so RetroArch's own
Achievements login writes `cheevos_username`/`cheevos_password` straight into
`.retroarch/retroarch.cfg`. No separate credentials source or mode-patcher is needed — the
existing Onion-style `retroarch_cfg.py` flow (`cheevos_custom_host`, `cheevos_enable`,
etc.) applies unchanged.

## Build

```
./linux/onion/fetch_runtime.sh # once
./linux/onion/fetch_vendor.sh # once
./linux/allium/build_bundle.sh
```

Produces `linux/allium/dist/RAOfflineProxy-Allium-v<VER>.zip`, extracted over the SD card
root so the app lands in `/mnt/SDCARD/Apps/RAOfflineProxy.pak`.

## Hardware coverage

Allium runs only on the Miyoo Mini, Mini Plus and Mini Flip, and the armv7 runtime, native
lib and SDL2 bundled here cover all three. There is no uncovered hardware: unlike spruce,
whose 64-bit devices this stack cannot reach, Allium has no targets beyond the Miyoo Mini
family.

Verified on a Miyoo Mini Plus running Allium v1.0.1.

## Self-update

Supported, through the same flow every other zip-based target uses. The archive installer
was layout-agnostic apart from one hardcoded path, so it takes an `archive_root` argument
instead: `App` for Onion and spruce, `Apps` for this bundle's `.pak`. Everything else —
atomic replace, rollback on failure, preserving `data/` across a same-major update — is
shared.

Releasing therefore requires attaching `RAOfflineProxy-Allium-v<VER>.zip` to the GitHub
release. `find_platform_asset_url()` matches on `allium` + `.zip`, and a test pins the
in-archive layout (`Apps/RAOfflineProxy.pak`) to what `build_bundle.sh` produces, so a
rename on either side fails the suite rather than breaking updates on device.
16 changes: 16 additions & 0 deletions linux/allium/app/RAOfflineProxy.pak/autostart-launch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh
set -eu

appdir="$(cd "$(dirname "$0")" && pwd)"

. "$appdir/common.sh"

prepare_env

if ! resolve_python_bin; then
exit 0
fi

PYTHON_BIN="$RESOLVED_PYTHON_BIN"

run_backend "$PYTHON_BIN" boot-reconcile >/dev/null 2>&1 || true
Loading