akitaonrails/distrobox-gaming

Script to create a gaming focused Distrobox with all emulators pre-configured

Shell

294

486 commits

updated Sep 18, 2026

See the code

README

Distrobox Gaming

Ansible playbooks for an Arch-based distrobox named gaming. Sets up ES-DE, standalone emulators (shadPS4 for PS4, Dolphin for GC/Wii, PCSX2 for PS2, DuckStation for PS1, Flycast for Dreamcast, xemu for Xbox, RPCS3 for PS3, PPSSPP for PSP, Azahar for 3DS, Eden for Switch, Cemu for Wii U, RetroArch, and Supermodel for Sega Model 3), RetroArch cores, host-side Walker desktop launcher rendering/install scripts, DLC/patch batch installers for PS3 and Switch, per-game RPCS3 optimization configs, optional Wine-managed Xenia Manager for Xbox 360, Hedge Mod Manager for Sonic mods, optional native Unleashed Recompiled for Sonic Unleashed, and a minimal zsh + starship shell inside the box.

Beyond the core emulators, a large set of opt-in roles (all never-tagged, or run via a standalone install-*.yml playbook) add: Sega arcade (Model 1/2/3 via Wine frontends + Supermodel), native recomp/decomp ports (Ship of Harkinian, 2Ship2Harkinian, Starship, Render96ex, SpaghettiKart, Sonic P-06, Unleashed Recomp, PrBoom-Plus Doom II RT), Windows/Wine games (Colin McRae Rally, OutRun 2006, Sega Rally, GT5 Master Mod, Metal Gear Master Collection fixes, and more), and reproducible NexusMods mod-set roles per game. See docs/nexusmods.md, docs/external-installers.md, and docs/rebuild-runbook.md.

macOS

macos/ is a separate, native macOS baseline — ES-DE plus Dolphin, PCSX2 and PPSSPP over Homebrew, with its own small Ansible playbook. It shares no code with the Linux tree: no Distrobox, no Wine/Proton, no .so cores. Windows software is permanently out of its scope. See macos/README.md and macos/INSTALL.md.

Everything else in this file describes the Linux distrobox.

Quick Start

cd ansible
ansible-galaxy collection install -r collections/requirements.yml
cp host_vars/localhost.yml.example host_vars/localhost.yml
$EDITOR host_vars/localhost.yml
ansible-playbook site.yml

For a full run with optional Xbox 360/Xenia Manager:

ansible-playbook site.yml
ansible-playbook install-xenia.yml

Commands

All commands run from the ansible/ directory:

ansible-playbook site.yml              # full setup from scratch
ansible-playbook reset-configs.yml      # reset emulator configs without rebuilding
ansible-playbook backup.yml             # backup before destructive testing
ansible-playbook restore.yml            # restore from backup
ansible-playbook refresh-shadps4.yml    # update shadPS4 builds
ansible-playbook install-xenia.yml      # install/update Xenia Manager (optional)
ansible-playbook install-hedgemodmanager.yml  # install/update Hedge Mod Manager
ansible-playbook install-pc-racing.yml  # prepare/install optional Windows PC racing games
ansible-playbook install-outrun-2006.yml  # install/update OutRun 2006
ansible-playbook install-sega-rally-revo.yml  # install/update Sega Rally Revo
ansible-playbook install-sonic-p06.yml  # install/update Sonic Project '06
ansible-playbook install-unleashed-recomp.yml  # install/update Unleashed Recompiled

Tags allow running subsets:

ansible-playbook site.yml --tags check           # host path and UID/GID validation
ansible-playbook site.yml --tags create          # create the distrobox
ansible-playbook site.yml --tags bootstrap       # install pacman + AUR packages
ansible-playbook site.yml --tags shadps4         # install/update shadPS4
ansible-playbook site.yml --tags hedgemodmanager # install/update Hedge Mod Manager
ansible-playbook site.yml --tags configure       # configs, desktop entries, ES-DE
ansible-playbook site.yml --tags scripts         # deploy box helper scripts
ansible-playbook site.yml --tags shell           # deploy zsh + starship
ansible-playbook site.yml --tags verify          # post-setup assertions
ansible-playbook reset-configs.yml --tags esde     # reset only ES-DE
ansible-playbook reset-configs.yml --tags configs   # reset only emulator INIs
ansible-playbook reset-configs.yml --tags desktop   # reset only desktop entries
ansible-playbook reset-configs.yml --tags shell     # reset only zsh/starship

Opt-in roles (skipped by default)

These roles touch your specific ROM/NAS layout or perform large downloads, so they only run when the matching tag is explicitly passed:

ansible-playbook site.yml --tags dlcs            # install PS3 DLCs + Switch NSPs
ansible-playbook site.yml --tags cheats          # link Switch cheats to Eden
ansible-playbook site.yml --tags rpcs3_configs   # per-game RPCS3 tuning
ansible-playbook site.yml --tags retroarch       # download RA cores + assets
ansible-playbook site.yml --tags pcsx2_textures  # PCSX2 HD texture packs + per-game settings + .pnach patches
ansible-playbook site.yml --tags pc_racing       # prepare tested Windows PC racing games via Wine
ansible-playbook site.yml --tags sonic_p06       # install Sonic Project '06 via system Wine
ansible-playbook site.yml --tags unleashed_recomp # install native Unleashed Recompiled Flatpak
ansible-playbook site.yml --tags ogm             # render the ogm (omarchy-games-menu) catalog fragment

Path Configuration

All paths are configurable via Ansible variables. Defaults match the current machine's NAS layout:

dg_box_name: gaming
dg_host_uid: 1026                    # NAS requires this UID
dg_host_gid: 1026
dg_data_root: /mnt/data
dg_box_home: /mnt/data/distrobox/gaming
dg_external_games_root: /mnt/terachad/Emulators
dg_roms_final_root: "{{ dg_external_games_root }}/ROMS_FINAL"
dg_emudeck_root: "{{ dg_external_games_root }}/EmuDeck"
dg_bios_root: "{{ dg_emudeck_root }}/Emulation/bios"
dg_rom_root: "{{ dg_emudeck_root }}/roms"
dg_rom_heavy_root: "{{ dg_emudeck_root }}/roms_heavy"
dg_ps3_dlc_source: "{{ dg_rom_heavy_root }}/ps3-DLC"
dg_switch_updates_source: "{{ dg_rom_heavy_root }}/switch_updates"
dg_switch_cheats_source: "{{ dg_rom_heavy_root }}/switch_cheats"

For another machine, create ansible/host_vars/localhost.yml and override any variable. Or pass overrides on the command line:

ansible-playbook site.yml -e dg_data_root=/home/me/gaming -e dg_external_games_root=/media/games

GPU Preference (NVIDIA vs AMD iGPU)

On systems with both an NVIDIA dGPU and an AMD iGPU, emulators are forced to use NVIDIA by injecting VK_ICD_FILENAMES into every desktop launcher and ES-DE command. The distrobox is also created with --nvidia so NVIDIA drivers are bind-mounted into the container. Controlled by dg_nvidia_enabled: true in group_vars/all/gpu.yml. Set to false to disable.

For Steam/Proton, the launcher also exports LD_LIBRARY_PATH pointing only to an Ansible-managed extraction of the matching lib32-nvidia-utils package. Steam Runtime's entrypoint converts that into pressure-vessel app library paths before launching Proton. This avoids a distrobox --nvidia edge case where host 64-bit NVIDIA libraries can appear under /usr/lib32, breaking 32-bit DXVK games such as Sonic Adventure DX and Castlevania Anniversary Collection.

Steam game compatibility research is tracked in data/steam-proton-compat.json. Refresh it with scripts/build-steam-proton-db.py and record source-backed local fixes in data/steam-proton-overrides.json; see docs/steam-proton-compatibility.md.

Resetting Configs

If you screw up your emulator configs (ES-DE, DuckStation, PCSX2, etc.) and want to restore to Ansible-managed defaults without reinstalling the box:

ansible-playbook reset-configs.yml           # reset everything
ansible-playbook reset-configs.yml --tags esde    # reset only ES-DE
ansible-playbook reset-configs.yml --tags configs  # reset only emulator INIs
ansible-playbook reset-configs.yml --tags shell    # reset only zsh/starship

This re-applies seed_configs, desktop_apps, configure_esde, and shell_config roles. Existing files are backed up automatically before overwriting.

Backup and Restore

Before destructive testing (e.g. rebuilding from scratch):

ansible-playbook backup.yml     # commits container image + archives configs
ansible-playbook restore.yml    # prompts for timestamp, restores both

Backups are stored under $DG_BOX_HOME/backups/.

UID/GID and Permissions

The NAS requires UID/GID 1026 for file access. The check_host role asserts the host user matches dg_host_uid before proceeding. The container user inherits the host UID/GID through distrobox.

Override for another machine:

# ansible/host_vars/localhost.yml
dg_host_uid: 1000
dg_host_gid: 1000

What Gets Configured

Base setup

  • Arch-based distrobox named gaming with --nvidia drivers bind-mounted
  • Pacman and AUR emulator packages (see group_vars/all/packages.yml)
  • ES-DE (emulationstation-de) as the frontend
  • RetroArch plus 25 buildbot cores (fbneo, mednafen variants, etc.) and all 8 asset packs (info, assets, autoconfig, cheats, databases, shaders, overlays) — ~760 MB total
  • Atari 2600, 5200, 7800 and Lynx as opt-in ES-DE systems (dg_atari_enabled, off by default) on cores the list already carried (docs/atari.md)
  • Minimal zsh + starship prompt inside the box

Per-emulator

  • Flycast high-resolution wrapper at $DG_BOX_HOME/bin/flycast-hires
  • PCSX2: Vulkan @ 4x upscale (4K from PS2 480p), widescreen 16:9, 16x AF, PS2 bilinear filtering, built-in widescreen patches enabled, full Xbox-style Pad1 binding via SDL backend, Select+Start shutdown hotkey
  • Dolphin 8BitDo Ultimate 2 defaults for GameCube and Wii profiles
  • DuckStation Vulkan/PGXP/widescreen defaults
  • xemu config plus BIOS/HDD links from $DG_BIOS_ROOT
  • shadPS4 wrapper launching QtLauncher-managed builds, Driveclub-specific CUSA00003.toml config with v1.28 patch XML, PS4 11.00 sys_module symlinks

DLCs, patches, and per-game tuning

  • PS3 DLCs and patches: install_dlcs role batch-extracts every .pkg from $DG_PS3_DLC_SOURCE into RPCS3's dev_hdd0/game/ — bypasses the GUI-only installer limitation

  • Switch updates and DLC: same role extracts NSPs from $DG_SWITCH_UPDATES_SOURCE into Eden's NAND at ~/.local/share/eden/nand/user/Contents/registered/

  • Switch cheats: switch_cheats role symlinks Atmosphere-format cheats from $DG_SWITCH_CHEATS_SOURCE into Eden's load path

  • Per-game RPCS3 configs: rpcs3_per_game_configs role scans installed PS3 games, queries the RPCS3 compatibility API, and writes tuned custom_configs/<TITLE_ID>_config.yml for games with "Ingame" or "Loadable" status. Hand-curated overrides for known-problematic titles (Gran Turismo 6, Gran Turismo 5, Metal Gear Solid 4).

  • PCSX2 HD texture packs + per-game settings + .pnach patches: pcsx2_textures role symlinks per-game texture replacement directories into ~/.config/PCSX2/textures/<SERIAL>/replacements/<link_as>/ (no copy — textures live on NAS, PCSX2 caches in RAM after first load), symlinks .pnach patch files into ~/.config/PCSX2/patches/, mass-symlinks ~/.config/PCSX2/cheats/ from a NAS cheats source, downloads a curated list of public .pnach URLs (e.g. Silent's GT4 USA patches from his GitHub), and writes per-game override INIs to ~/.config/PCSX2/gamesettings/<SERIAL>.ini. Initial configs cover Gran Turismo 4 (SCUS-97328) with Silentwarior112's HD HUD/UI pack + update 2.1

    • blocky-haze-fix overlay + Silent's adjusted triggers / GT3 cam / far chase cam patches, and Enthusia Professional Racing (SLUS-20967) HD textures. Adding more games is a YAML data change to dg_pcsx2_texture_packs, dg_pcsx2_per_game_settings, dg_pcsx2_extra_patches, and dg_pcsx2_patch_urls in group_vars/all/pcsx2.yml.

    Texture pack updates are a manual process — the source forums (GTPlanet, Nexus Mods, Silent's Blog) are Cloudflare-walled and Drive/MEGA links throttle scripted downloads. Check periodically:

    When a new version drops, download manually and drop into the existing pack directory in your NAS — the role re-symlinks on next run.

Host-side launchers

  • Repo-managed Walker desktop entries for every emulator, defined as data in group_vars/all/launchers.yml and rendered via a single Jinja2 template. Each Exec line is wrapped with the NVIDIA-preference env vars.
  • Entries cover: ES-DE, Dolphin, DuckStation, PCSX2, PPSSPP, RPCS3, xemu, Eden, Cemu, Vita3K, shadPS4 (Driveclub + No Patch + GUI), Flycast, Xenia Manager, Sonic P-06, and Unleashed Recompiled when their wrappers exist.
  • Ansible renders entries into config/desktop/rendered/; it does not write into the host applications directory from inside the distrobox. Install or refresh host menu entries from the host with:
scripts/install-host-launchers.sh

The script validates every rendered .desktop file, skips optional apps that are not installed in the box, removes stale installed entries for missing optional apps, and restarts Walker if it is running.

Optional

  • Wine-managed Xenia Manager with .NET/VC++ runtimes for Xbox 360

Helper Scripts (manual use)

The install_dlcs role also deploys standalone scripts into the box that you can run manually for advanced tasks:

# List / download missing PS3 patches from PSN's public update server
python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
    "$DG_ROM_HEAVY_ROOT/ps3" \
    --dlc-dir "$DG_PS3_DLC_SOURCE" --list

python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
    "$DG_ROM_HEAVY_ROOT/ps3" \
    --dlc-dir "$DG_PS3_DLC_SOURCE" \
    --download-dir "$DG_BOX_HOME/dlc-temp" --download

# List outdated Switch games (Nintendo's CDN needs console auth, so no download)
python3 $DG_BOX_HOME/scripts/check_switch_updates.py \
    "$DG_ROM_HEAVY_ROOT/switch" \
    --updates-dir "$DG_SWITCH_UPDATES_SOURCE"

# Reorganize a messy switch_updates dump into per-title-ID folders
# (handles .nsp/.nsz/.xci/.xcz; mods and non-patch files are left alone)
python3 $DG_BOX_HOME/scripts/reorganize_switch_nsps.py \
    "$DG_SWITCH_UPDATES_SOURCE" --dry-run

Note on Switch updates: Nintendo's update CDN requires device-specific certificates from a hacked Switch. check_switch_updates.py only reports what's outdated (using the public blawar/titledb version database) — you source the NSPs yourself.

Full PS3 update workflow

  1. Check what's outdated:
    python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
        $DG_ROM_HEAVY_ROOT/ps3 --dlc-dir $DG_ROM_HEAVY_ROOT/ps3-DLC --list
    
  2. Download missing patches to a temp dir (keeps the NAS dir read-only until you review):
    python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
        $DG_ROM_HEAVY_ROOT/ps3 --dlc-dir $DG_ROM_HEAVY_ROOT/ps3-DLC \
        --download-dir $DG_BOX_HOME/dlc-temp --download
    
  3. Review $DG_BOX_HOME/dlc-temp, then copy into the canonical cache:
    rsync -av $DG_BOX_HOME/dlc-temp/ $DG_ROM_HEAVY_ROOT/ps3-DLC/
    
  4. Re-run the install_dlcs role to extract them into RPCS3:
    cd ansible && ansible-playbook site.yml --tags dlcs
    

The extract_ps3_dlc.py extractor uses the PKG's filename version (e.g. -A0122-V0100-) and compares against the destination's PARAM.SFO VERSION to decide whether to re-extract. Re-running after all patches are applied is a no-op.

Capping a game at a specific patch version

Some PS3 games regress on current RPCS3 when patched to the latest version (GT6 is notorious — older RPCS3 builds broke above 1.12 or so). To cap a game at a specific patch level:

# Wipe the current patch content dir so the version check doesn't block
rm -rf $DG_BOX_HOME/.config/rpcs3/dev_hdd0/game/<CONTENT_ID>

# Re-extract only patches up to the target version
python3 $DG_BOX_HOME/scripts/extract_ps3_dlc.py \
    $DG_ROM_HEAVY_ROOT/ps3-DLC/<TITLE_ID> \
    --max-version 01.12

--max-version skips any patch PKG whose filename-encoded version exceeds the limit. Without the rm -rf first, the version-aware idempotency check would refuse to downgrade.

PS4 Game Layout

The expected layout is clean extracted title directories, not raw .pkg files:

$DG_PS4_ROM_ROOT/
  CUSA00003/
    eboot.bin
    ...

Xenia Manager

Xbox 360 support uses Xenia Manager inside a dedicated Wine prefix. ansible-playbook install-xenia.yml will:

  • Enable multilib inside the box
  • Install wine and winetricks
  • Create the Wine prefix with .NET and VC++ runtimes
  • Download the latest Xenia Manager release
  • Write the launcher wrapper and render its desktop entry

After that, launch Xenia Manager and use its Manage page to install Canary.

Hedge Mod Manager

Sonic mod support uses Hedge Mod Manager 8 built natively inside the distrobox, not host Flatpak. The default site.yml run installs it; rerun only that role with:

ansible-playbook install-hedgemodmanager.yml

The wrapper is written to {{ dg_box_home }}/bin/hedge-mod-manager. It sees the same Steam install and external library paths as Steam inside the box, including the Proton prefixes under steamapps/compatdata.

PC Racing Games

Windows PC racing games are optional and live outside the normal rebuild path. They use system Wine inside the distrobox:

ansible-playbook install-pc-racing.yml

The install root is {{ dg_pc_racing_install_root }}; per-game prefixes stay under {{ dg_pc_racing_prefix_root }}. Installer GUIs are only launched when explicitly requested with -e dg_pc_racing_run_installers=true.

Sonic Project '06

Sonic P-06 is an optional Windows Unity fangame install managed outside Steam with system Wine, DXVK, core fonts, GStreamer codecs, and a dedicated prefix:

ansible-playbook install-sonic-p06.yml

The source is the already extracted Silver Release under {{ dg_sonic_p06_source_dir }}. The managed copy lives at {{ dg_sonic_p06_install_root }}.

Project Structure

ansible/                            # Ansible playbooks and roles (primary)
  site.yml                          # full setup playbook
  reset-configs.yml                 # config-only reset playbook
  backup.yml / restore.yml          # backup and restore
  refresh-shadps4.yml               # standalone shadPS4 update
  install-xenia.yml                 # standalone Xenia Manager install
  install-hedgemodmanager.yml       # standalone Hedge Mod Manager install
  install-pc-racing.yml             # optional Windows PC racing setup
  install-outrun-2006.yml           # focused OutRun 2006 install
  install-sega-rally-revo.yml       # focused Sega Rally Revo install
  install-sonic-p06.yml             # optional Sonic Project '06 setup
  install-unleashed-recomp.yml      # optional Unleashed Recompiled install
  group_vars/all/                   # all dg_* variable defaults
    main.yml                        # paths, UID/GID, box identity
    packages.yml                    # pacman + AUR package lists
    emulators.yml                   # per-emulator INI settings
    esde.yml                        # ES-DE system definitions
    launchers.yml                   # rendered host desktop launcher definitions
    ogm.yml                         # ogm (omarchy-games-menu) catalog metadata
    gpu.yml                         # NVIDIA preference config
    shadps4.yml                     # shadPS4 release / path config
    xenia.yml                       # Xenia Manager config
    hedgemodmanager.yml             # Hedge Mod Manager source-build config
    pc_racing.yml                   # Windows PC racing source/install metadata
    sonic_p06.yml                   # Sonic Project '06 Wine config
    unleashed_recomp.yml            # Unleashed Recompiled source staging config
    pcsx2.yml                       # PCSX2 texture packs and per-game overrides
  host_vars/localhost.yml.example   # machine-specific overrides template
  roles/                            # one role per setup phase
    check_host/                     # host validation
    create_box/                     # distrobox creation (--nvidia)
    bootstrap_packages/             # pacman + AUR packages
    link_storage/                   # BIOS/firmware symlinks
    seed_configs/                   # emulator INI settings, wrappers
    scripts_in_box/                 # deploy Python helpers into box
    install_dlcs/                   # PS3 PKG + Switch NSP batch install
    switch_cheats/                  # symlink cheats into Eden load path
    rpcs3_per_game_configs/         # per-title RPCS3 tuning from API
    retroarch_extras/               # 21 buildbot cores + 8 asset packs
    pcsx2_textures/                 # PCSX2 HD textures + per-game settings + .pnach patches
    desktop_apps/                   # .desktop entry rendering
    configure_esde/                 # ES-DE custom systems XML
    shell_config/                   # minimal zsh + starship
    verify/                         # post-setup assertions
    refresh_shadps4/                # shadPS4 GitHub release management
    install_xenia/                  # Wine prefix and Xenia Manager
    install_hedgemodmanager/        # native HMM 8 source build
    install_pc_racing/              # Wine wrappers for tested Windows racing games
    install_sonic_p06/              # Wine wrapper for Sonic Project '06
    install_unleashed_recomp/       # native Unleashed Recompiled Flatpak install
    ogm_catalog/                    # host-side ogm (omarchy-games-menu) catalog fragment
scripts/                            # helper scripts invoked by the Ansible roles
config/                             # live config source trees (emulator INIs, ES-DE, desktop templates)
docs/                               # historical notes and focused docs

Documentation

Core setup & rebuild:

Mods, patches & HD textures:

Windows / Wine games:

Arcade & ray-traced ports:

Xbox 360 & per-game tuning:

Historical notes:

Safety Rules

This repo does not provide ROMs, BIOS files, firmware, keys, or game packages.

Playbooks only detect, link, and configure files that already exist on your machine. They should not delete ROMs, BIOS, saves, firmware, or game data.

Generated emulator state, shader caches, saves, logs, firmware modules, and ROMs must not be committed.

Contributors

akitaonrails

480 commits

samirhvbr

6 commits

akitaonrails/distrobox-gaming

Script to create a gaming focused Distrobox with all emulators pre-configured

Shell

294

486 commits

updated Sep 18, 2026

See the code

README

Distrobox Gaming

Ansible playbooks for an Arch-based distrobox named gaming. Sets up ES-DE, standalone emulators (shadPS4 for PS4, Dolphin for GC/Wii, PCSX2 for PS2, DuckStation for PS1, Flycast for Dreamcast, xemu for Xbox, RPCS3 for PS3, PPSSPP for PSP, Azahar for 3DS, Eden for Switch, Cemu for Wii U, RetroArch, and Supermodel for Sega Model 3), RetroArch cores, host-side Walker desktop launcher rendering/install scripts, DLC/patch batch installers for PS3 and Switch, per-game RPCS3 optimization configs, optional Wine-managed Xenia Manager for Xbox 360, Hedge Mod Manager for Sonic mods, optional native Unleashed Recompiled for Sonic Unleashed, and a minimal zsh + starship shell inside the box.

Beyond the core emulators, a large set of opt-in roles (all never-tagged, or run via a standalone install-*.yml playbook) add: Sega arcade (Model 1/2/3 via Wine frontends + Supermodel), native recomp/decomp ports (Ship of Harkinian, 2Ship2Harkinian, Starship, Render96ex, SpaghettiKart, Sonic P-06, Unleashed Recomp, PrBoom-Plus Doom II RT), Windows/Wine games (Colin McRae Rally, OutRun 2006, Sega Rally, GT5 Master Mod, Metal Gear Master Collection fixes, and more), and reproducible NexusMods mod-set roles per game. See docs/nexusmods.md, docs/external-installers.md, and docs/rebuild-runbook.md.

macOS

macos/ is a separate, native macOS baseline — ES-DE plus Dolphin, PCSX2 and PPSSPP over Homebrew, with its own small Ansible playbook. It shares no code with the Linux tree: no Distrobox, no Wine/Proton, no .so cores. Windows software is permanently out of its scope. See macos/README.md and macos/INSTALL.md.

Everything else in this file describes the Linux distrobox.

Quick Start

cd ansible
ansible-galaxy collection install -r collections/requirements.yml
cp host_vars/localhost.yml.example host_vars/localhost.yml
$EDITOR host_vars/localhost.yml
ansible-playbook site.yml

For a full run with optional Xbox 360/Xenia Manager:

ansible-playbook site.yml
ansible-playbook install-xenia.yml

Commands

All commands run from the ansible/ directory:

ansible-playbook site.yml              # full setup from scratch
ansible-playbook reset-configs.yml      # reset emulator configs without rebuilding
ansible-playbook backup.yml             # backup before destructive testing
ansible-playbook restore.yml            # restore from backup
ansible-playbook refresh-shadps4.yml    # update shadPS4 builds
ansible-playbook install-xenia.yml      # install/update Xenia Manager (optional)
ansible-playbook install-hedgemodmanager.yml  # install/update Hedge Mod Manager
ansible-playbook install-pc-racing.yml  # prepare/install optional Windows PC racing games
ansible-playbook install-outrun-2006.yml  # install/update OutRun 2006
ansible-playbook install-sega-rally-revo.yml  # install/update Sega Rally Revo
ansible-playbook install-sonic-p06.yml  # install/update Sonic Project '06
ansible-playbook install-unleashed-recomp.yml  # install/update Unleashed Recompiled

Tags allow running subsets:

ansible-playbook site.yml --tags check           # host path and UID/GID validation
ansible-playbook site.yml --tags create          # create the distrobox
ansible-playbook site.yml --tags bootstrap       # install pacman + AUR packages
ansible-playbook site.yml --tags shadps4         # install/update shadPS4
ansible-playbook site.yml --tags hedgemodmanager # install/update Hedge Mod Manager
ansible-playbook site.yml --tags configure       # configs, desktop entries, ES-DE
ansible-playbook site.yml --tags scripts         # deploy box helper scripts
ansible-playbook site.yml --tags shell           # deploy zsh + starship
ansible-playbook site.yml --tags verify          # post-setup assertions
ansible-playbook reset-configs.yml --tags esde     # reset only ES-DE
ansible-playbook reset-configs.yml --tags configs   # reset only emulator INIs
ansible-playbook reset-configs.yml --tags desktop   # reset only desktop entries
ansible-playbook reset-configs.yml --tags shell     # reset only zsh/starship

Opt-in roles (skipped by default)

These roles touch your specific ROM/NAS layout or perform large downloads, so they only run when the matching tag is explicitly passed:

ansible-playbook site.yml --tags dlcs            # install PS3 DLCs + Switch NSPs
ansible-playbook site.yml --tags cheats          # link Switch cheats to Eden
ansible-playbook site.yml --tags rpcs3_configs   # per-game RPCS3 tuning
ansible-playbook site.yml --tags retroarch       # download RA cores + assets
ansible-playbook site.yml --tags pcsx2_textures  # PCSX2 HD texture packs + per-game settings + .pnach patches
ansible-playbook site.yml --tags pc_racing       # prepare tested Windows PC racing games via Wine
ansible-playbook site.yml --tags sonic_p06       # install Sonic Project '06 via system Wine
ansible-playbook site.yml --tags unleashed_recomp # install native Unleashed Recompiled Flatpak
ansible-playbook site.yml --tags ogm             # render the ogm (omarchy-games-menu) catalog fragment

Path Configuration

All paths are configurable via Ansible variables. Defaults match the current machine's NAS layout:

dg_box_name: gaming
dg_host_uid: 1026                    # NAS requires this UID
dg_host_gid: 1026
dg_data_root: /mnt/data
dg_box_home: /mnt/data/distrobox/gaming
dg_external_games_root: /mnt/terachad/Emulators
dg_roms_final_root: "{{ dg_external_games_root }}/ROMS_FINAL"
dg_emudeck_root: "{{ dg_external_games_root }}/EmuDeck"
dg_bios_root: "{{ dg_emudeck_root }}/Emulation/bios"
dg_rom_root: "{{ dg_emudeck_root }}/roms"
dg_rom_heavy_root: "{{ dg_emudeck_root }}/roms_heavy"
dg_ps3_dlc_source: "{{ dg_rom_heavy_root }}/ps3-DLC"
dg_switch_updates_source: "{{ dg_rom_heavy_root }}/switch_updates"
dg_switch_cheats_source: "{{ dg_rom_heavy_root }}/switch_cheats"

For another machine, create ansible/host_vars/localhost.yml and override any variable. Or pass overrides on the command line:

ansible-playbook site.yml -e dg_data_root=/home/me/gaming -e dg_external_games_root=/media/games

GPU Preference (NVIDIA vs AMD iGPU)

On systems with both an NVIDIA dGPU and an AMD iGPU, emulators are forced to use NVIDIA by injecting VK_ICD_FILENAMES into every desktop launcher and ES-DE command. The distrobox is also created with --nvidia so NVIDIA drivers are bind-mounted into the container. Controlled by dg_nvidia_enabled: true in group_vars/all/gpu.yml. Set to false to disable.

For Steam/Proton, the launcher also exports LD_LIBRARY_PATH pointing only to an Ansible-managed extraction of the matching lib32-nvidia-utils package. Steam Runtime's entrypoint converts that into pressure-vessel app library paths before launching Proton. This avoids a distrobox --nvidia edge case where host 64-bit NVIDIA libraries can appear under /usr/lib32, breaking 32-bit DXVK games such as Sonic Adventure DX and Castlevania Anniversary Collection.

Steam game compatibility research is tracked in data/steam-proton-compat.json. Refresh it with scripts/build-steam-proton-db.py and record source-backed local fixes in data/steam-proton-overrides.json; see docs/steam-proton-compatibility.md.

Resetting Configs

If you screw up your emulator configs (ES-DE, DuckStation, PCSX2, etc.) and want to restore to Ansible-managed defaults without reinstalling the box:

ansible-playbook reset-configs.yml           # reset everything
ansible-playbook reset-configs.yml --tags esde    # reset only ES-DE
ansible-playbook reset-configs.yml --tags configs  # reset only emulator INIs
ansible-playbook reset-configs.yml --tags shell    # reset only zsh/starship

This re-applies seed_configs, desktop_apps, configure_esde, and shell_config roles. Existing files are backed up automatically before overwriting.

Backup and Restore

Before destructive testing (e.g. rebuilding from scratch):

ansible-playbook backup.yml     # commits container image + archives configs
ansible-playbook restore.yml    # prompts for timestamp, restores both

Backups are stored under $DG_BOX_HOME/backups/.

UID/GID and Permissions

The NAS requires UID/GID 1026 for file access. The check_host role asserts the host user matches dg_host_uid before proceeding. The container user inherits the host UID/GID through distrobox.

Override for another machine:

# ansible/host_vars/localhost.yml
dg_host_uid: 1000
dg_host_gid: 1000

What Gets Configured

Base setup

  • Arch-based distrobox named gaming with --nvidia drivers bind-mounted
  • Pacman and AUR emulator packages (see group_vars/all/packages.yml)
  • ES-DE (emulationstation-de) as the frontend
  • RetroArch plus 25 buildbot cores (fbneo, mednafen variants, etc.) and all 8 asset packs (info, assets, autoconfig, cheats, databases, shaders, overlays) — ~760 MB total
  • Atari 2600, 5200, 7800 and Lynx as opt-in ES-DE systems (dg_atari_enabled, off by default) on cores the list already carried (docs/atari.md)
  • Minimal zsh + starship prompt inside the box

Per-emulator

  • Flycast high-resolution wrapper at $DG_BOX_HOME/bin/flycast-hires
  • PCSX2: Vulkan @ 4x upscale (4K from PS2 480p), widescreen 16:9, 16x AF, PS2 bilinear filtering, built-in widescreen patches enabled, full Xbox-style Pad1 binding via SDL backend, Select+Start shutdown hotkey
  • Dolphin 8BitDo Ultimate 2 defaults for GameCube and Wii profiles
  • DuckStation Vulkan/PGXP/widescreen defaults
  • xemu config plus BIOS/HDD links from $DG_BIOS_ROOT
  • shadPS4 wrapper launching QtLauncher-managed builds, Driveclub-specific CUSA00003.toml config with v1.28 patch XML, PS4 11.00 sys_module symlinks

DLCs, patches, and per-game tuning

  • PS3 DLCs and patches: install_dlcs role batch-extracts every .pkg from $DG_PS3_DLC_SOURCE into RPCS3's dev_hdd0/game/ — bypasses the GUI-only installer limitation

  • Switch updates and DLC: same role extracts NSPs from $DG_SWITCH_UPDATES_SOURCE into Eden's NAND at ~/.local/share/eden/nand/user/Contents/registered/

  • Switch cheats: switch_cheats role symlinks Atmosphere-format cheats from $DG_SWITCH_CHEATS_SOURCE into Eden's load path

  • Per-game RPCS3 configs: rpcs3_per_game_configs role scans installed PS3 games, queries the RPCS3 compatibility API, and writes tuned custom_configs/<TITLE_ID>_config.yml for games with "Ingame" or "Loadable" status. Hand-curated overrides for known-problematic titles (Gran Turismo 6, Gran Turismo 5, Metal Gear Solid 4).

  • PCSX2 HD texture packs + per-game settings + .pnach patches: pcsx2_textures role symlinks per-game texture replacement directories into ~/.config/PCSX2/textures/<SERIAL>/replacements/<link_as>/ (no copy — textures live on NAS, PCSX2 caches in RAM after first load), symlinks .pnach patch files into ~/.config/PCSX2/patches/, mass-symlinks ~/.config/PCSX2/cheats/ from a NAS cheats source, downloads a curated list of public .pnach URLs (e.g. Silent's GT4 USA patches from his GitHub), and writes per-game override INIs to ~/.config/PCSX2/gamesettings/<SERIAL>.ini. Initial configs cover Gran Turismo 4 (SCUS-97328) with Silentwarior112's HD HUD/UI pack + update 2.1

    • blocky-haze-fix overlay + Silent's adjusted triggers / GT3 cam / far chase cam patches, and Enthusia Professional Racing (SLUS-20967) HD textures. Adding more games is a YAML data change to dg_pcsx2_texture_packs, dg_pcsx2_per_game_settings, dg_pcsx2_extra_patches, and dg_pcsx2_patch_urls in group_vars/all/pcsx2.yml.

    Texture pack updates are a manual process — the source forums (GTPlanet, Nexus Mods, Silent's Blog) are Cloudflare-walled and Drive/MEGA links throttle scripted downloads. Check periodically:

    When a new version drops, download manually and drop into the existing pack directory in your NAS — the role re-symlinks on next run.

Host-side launchers

  • Repo-managed Walker desktop entries for every emulator, defined as data in group_vars/all/launchers.yml and rendered via a single Jinja2 template. Each Exec line is wrapped with the NVIDIA-preference env vars.
  • Entries cover: ES-DE, Dolphin, DuckStation, PCSX2, PPSSPP, RPCS3, xemu, Eden, Cemu, Vita3K, shadPS4 (Driveclub + No Patch + GUI), Flycast, Xenia Manager, Sonic P-06, and Unleashed Recompiled when their wrappers exist.
  • Ansible renders entries into config/desktop/rendered/; it does not write into the host applications directory from inside the distrobox. Install or refresh host menu entries from the host with:
scripts/install-host-launchers.sh

The script validates every rendered .desktop file, skips optional apps that are not installed in the box, removes stale installed entries for missing optional apps, and restarts Walker if it is running.

Optional

  • Wine-managed Xenia Manager with .NET/VC++ runtimes for Xbox 360

Helper Scripts (manual use)

The install_dlcs role also deploys standalone scripts into the box that you can run manually for advanced tasks:

# List / download missing PS3 patches from PSN's public update server
python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
    "$DG_ROM_HEAVY_ROOT/ps3" \
    --dlc-dir "$DG_PS3_DLC_SOURCE" --list

python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
    "$DG_ROM_HEAVY_ROOT/ps3" \
    --dlc-dir "$DG_PS3_DLC_SOURCE" \
    --download-dir "$DG_BOX_HOME/dlc-temp" --download

# List outdated Switch games (Nintendo's CDN needs console auth, so no download)
python3 $DG_BOX_HOME/scripts/check_switch_updates.py \
    "$DG_ROM_HEAVY_ROOT/switch" \
    --updates-dir "$DG_SWITCH_UPDATES_SOURCE"

# Reorganize a messy switch_updates dump into per-title-ID folders
# (handles .nsp/.nsz/.xci/.xcz; mods and non-patch files are left alone)
python3 $DG_BOX_HOME/scripts/reorganize_switch_nsps.py \
    "$DG_SWITCH_UPDATES_SOURCE" --dry-run

Note on Switch updates: Nintendo's update CDN requires device-specific certificates from a hacked Switch. check_switch_updates.py only reports what's outdated (using the public blawar/titledb version database) — you source the NSPs yourself.

Full PS3 update workflow

  1. Check what's outdated:
    python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
        $DG_ROM_HEAVY_ROOT/ps3 --dlc-dir $DG_ROM_HEAVY_ROOT/ps3-DLC --list
    
  2. Download missing patches to a temp dir (keeps the NAS dir read-only until you review):
    python3 $DG_BOX_HOME/scripts/check_ps3_updates.py \
        $DG_ROM_HEAVY_ROOT/ps3 --dlc-dir $DG_ROM_HEAVY_ROOT/ps3-DLC \
        --download-dir $DG_BOX_HOME/dlc-temp --download
    
  3. Review $DG_BOX_HOME/dlc-temp, then copy into the canonical cache:
    rsync -av $DG_BOX_HOME/dlc-temp/ $DG_ROM_HEAVY_ROOT/ps3-DLC/
    
  4. Re-run the install_dlcs role to extract them into RPCS3:
    cd ansible && ansible-playbook site.yml --tags dlcs
    

The extract_ps3_dlc.py extractor uses the PKG's filename version (e.g. -A0122-V0100-) and compares against the destination's PARAM.SFO VERSION to decide whether to re-extract. Re-running after all patches are applied is a no-op.

Capping a game at a specific patch version

Some PS3 games regress on current RPCS3 when patched to the latest version (GT6 is notorious — older RPCS3 builds broke above 1.12 or so). To cap a game at a specific patch level:

# Wipe the current patch content dir so the version check doesn't block
rm -rf $DG_BOX_HOME/.config/rpcs3/dev_hdd0/game/<CONTENT_ID>

# Re-extract only patches up to the target version
python3 $DG_BOX_HOME/scripts/extract_ps3_dlc.py \
    $DG_ROM_HEAVY_ROOT/ps3-DLC/<TITLE_ID> \
    --max-version 01.12

--max-version skips any patch PKG whose filename-encoded version exceeds the limit. Without the rm -rf first, the version-aware idempotency check would refuse to downgrade.

PS4 Game Layout

The expected layout is clean extracted title directories, not raw .pkg files:

$DG_PS4_ROM_ROOT/
  CUSA00003/
    eboot.bin
    ...

Xenia Manager

Xbox 360 support uses Xenia Manager inside a dedicated Wine prefix. ansible-playbook install-xenia.yml will:

  • Enable multilib inside the box
  • Install wine and winetricks
  • Create the Wine prefix with .NET and VC++ runtimes
  • Download the latest Xenia Manager release
  • Write the launcher wrapper and render its desktop entry

After that, launch Xenia Manager and use its Manage page to install Canary.

Hedge Mod Manager

Sonic mod support uses Hedge Mod Manager 8 built natively inside the distrobox, not host Flatpak. The default site.yml run installs it; rerun only that role with:

ansible-playbook install-hedgemodmanager.yml

The wrapper is written to {{ dg_box_home }}/bin/hedge-mod-manager. It sees the same Steam install and external library paths as Steam inside the box, including the Proton prefixes under steamapps/compatdata.

PC Racing Games

Windows PC racing games are optional and live outside the normal rebuild path. They use system Wine inside the distrobox:

ansible-playbook install-pc-racing.yml

The install root is {{ dg_pc_racing_install_root }}; per-game prefixes stay under {{ dg_pc_racing_prefix_root }}. Installer GUIs are only launched when explicitly requested with -e dg_pc_racing_run_installers=true.

Sonic Project '06

Sonic P-06 is an optional Windows Unity fangame install managed outside Steam with system Wine, DXVK, core fonts, GStreamer codecs, and a dedicated prefix:

ansible-playbook install-sonic-p06.yml

The source is the already extracted Silver Release under {{ dg_sonic_p06_source_dir }}. The managed copy lives at {{ dg_sonic_p06_install_root }}.

Project Structure

ansible/                            # Ansible playbooks and roles (primary)
  site.yml                          # full setup playbook
  reset-configs.yml                 # config-only reset playbook
  backup.yml / restore.yml          # backup and restore
  refresh-shadps4.yml               # standalone shadPS4 update
  install-xenia.yml                 # standalone Xenia Manager install
  install-hedgemodmanager.yml       # standalone Hedge Mod Manager install
  install-pc-racing.yml             # optional Windows PC racing setup
  install-outrun-2006.yml           # focused OutRun 2006 install
  install-sega-rally-revo.yml       # focused Sega Rally Revo install
  install-sonic-p06.yml             # optional Sonic Project '06 setup
  install-unleashed-recomp.yml      # optional Unleashed Recompiled install
  group_vars/all/                   # all dg_* variable defaults
    main.yml                        # paths, UID/GID, box identity
    packages.yml                    # pacman + AUR package lists
    emulators.yml                   # per-emulator INI settings
    esde.yml                        # ES-DE system definitions
    launchers.yml                   # rendered host desktop launcher definitions
    ogm.yml                         # ogm (omarchy-games-menu) catalog metadata
    gpu.yml                         # NVIDIA preference config
    shadps4.yml                     # shadPS4 release / path config
    xenia.yml                       # Xenia Manager config
    hedgemodmanager.yml             # Hedge Mod Manager source-build config
    pc_racing.yml                   # Windows PC racing source/install metadata
    sonic_p06.yml                   # Sonic Project '06 Wine config
    unleashed_recomp.yml            # Unleashed Recompiled source staging config
    pcsx2.yml                       # PCSX2 texture packs and per-game overrides
  host_vars/localhost.yml.example   # machine-specific overrides template
  roles/                            # one role per setup phase
    check_host/                     # host validation
    create_box/                     # distrobox creation (--nvidia)
    bootstrap_packages/             # pacman + AUR packages
    link_storage/                   # BIOS/firmware symlinks
    seed_configs/                   # emulator INI settings, wrappers
    scripts_in_box/                 # deploy Python helpers into box
    install_dlcs/                   # PS3 PKG + Switch NSP batch install
    switch_cheats/                  # symlink cheats into Eden load path
    rpcs3_per_game_configs/         # per-title RPCS3 tuning from API
    retroarch_extras/               # 21 buildbot cores + 8 asset packs
    pcsx2_textures/                 # PCSX2 HD textures + per-game settings + .pnach patches
    desktop_apps/                   # .desktop entry rendering
    configure_esde/                 # ES-DE custom systems XML
    shell_config/                   # minimal zsh + starship
    verify/                         # post-setup assertions
    refresh_shadps4/                # shadPS4 GitHub release management
    install_xenia/                  # Wine prefix and Xenia Manager
    install_hedgemodmanager/        # native HMM 8 source build
    install_pc_racing/              # Wine wrappers for tested Windows racing games
    install_sonic_p06/              # Wine wrapper for Sonic Project '06
    install_unleashed_recomp/       # native Unleashed Recompiled Flatpak install
    ogm_catalog/                    # host-side ogm (omarchy-games-menu) catalog fragment
scripts/                            # helper scripts invoked by the Ansible roles
config/                             # live config source trees (emulator INIs, ES-DE, desktop templates)
docs/                               # historical notes and focused docs

Documentation

Core setup & rebuild:

Mods, patches & HD textures:

Windows / Wine games:

Arcade & ray-traced ports:

Xbox 360 & per-game tuning:

Historical notes:

Safety Rules

This repo does not provide ROMs, BIOS files, firmware, keys, or game packages.

Playbooks only detect, link, and configure files that already exist on your machine. They should not delete ROMs, BIOS, saves, firmware, or game data.

Generated emulator state, shader caches, saves, logs, firmware modules, and ROMs must not be committed.

Contributors

akitaonrails

480 commits

samirhvbr

6 commits

Languages

Shell

43.8%

Python

41.6%

Jinja

11.5%

C

2.2%