diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e72fc18..1902911 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -140,12 +140,13 @@ jobs: env: GROUT_VERSION: ${{ needs.prepare.outputs.version }} - - name: Package Batocera AMD64 - run: task package:batocera-amd64 + - name: Package AMD64 platforms + run: task package:batocera-amd64 package:retrodeck - name: Create distribution run: | cd dist/Batocera-amd64 && zip -r ../Grout-Batocera-amd64.zip Grout.sh Grout + cd dist/RetroDECK && zip -r ../Grout-RetroDECK.zip Grout.sh Grout - name: Upload artifacts uses: actions/upload-artifact@v4 @@ -153,6 +154,7 @@ jobs: name: amd64-artifacts path: | dist/Grout-Batocera-amd64.zip + dist/Grout-RetroDECK.zip build-x86: needs: prepare diff --git a/cfw/cfw.go b/cfw/cfw.go index b45cde6..f1b58e9 100644 --- a/cfw/cfw.go +++ b/cfw/cfw.go @@ -9,17 +9,18 @@ import ( type CFW string const ( - NextUI CFW = "NEXTUI" - MuOS CFW = "MUOS" - Knulli CFW = "KNULLI" - Spruce CFW = "SPRUCE" - ROCKNIX CFW = "ROCKNIX" - Trimui CFW = "TRIMUI" - Allium CFW = "ALLIUM" - Onion CFW = "ONION" - Koriki CFW = "KORIKI" - Batocera CFW = "BATOCERA" - MinUI CFW = "MINUI" + NextUI CFW = "NEXTUI" + MuOS CFW = "MUOS" + Knulli CFW = "KNULLI" + Spruce CFW = "SPRUCE" + ROCKNIX CFW = "ROCKNIX" + Trimui CFW = "TRIMUI" + Allium CFW = "ALLIUM" + Onion CFW = "ONION" + Koriki CFW = "KORIKI" + Batocera CFW = "BATOCERA" + MinUI CFW = "MINUI" + RetroDECK CFW = "RETRODECK" ) func GetCFW() CFW { @@ -27,18 +28,18 @@ func GetCFW() CFW { cfw := CFW(cfwEnv) switch cfw { - case MuOS, NextUI, Knulli, Spruce, ROCKNIX, Trimui, Allium, Onion, Koriki, Batocera, MinUI: + case MuOS, NextUI, Knulli, Spruce, ROCKNIX, Trimui, Allium, Onion, Koriki, Batocera, MinUI, RetroDECK: return cfw default: log.SetOutput(os.Stderr) - log.Fatalf("Unsupported CFW: '%s'. Valid options: NextUI, muOS, Knulli, Spruce, ROCKNIX, Trimui, Allium, Onion, Koriki, Batocera, MinUI", cfwEnv) + log.Fatalf("Unsupported CFW: '%s'. Valid options: NextUI, muOS, Knulli, Spruce, ROCKNIX, Trimui, Allium, Onion, Koriki, Batocera, MinUI, RetroDECK", cfwEnv) return "" } } func (c CFW) IsBasedOnEmulationStation() bool { switch c { - case Knulli, ROCKNIX, Batocera: + case Knulli, ROCKNIX, Batocera, RetroDECK: return true default: return false diff --git a/cfw/directories.go b/cfw/directories.go index 5d64867..7a9b7e3 100644 --- a/cfw/directories.go +++ b/cfw/directories.go @@ -9,6 +9,7 @@ import ( "grout/cfw/muos" "grout/cfw/nextui" "grout/cfw/onion" + "grout/cfw/retrodeck" "grout/cfw/rocknix" "grout/cfw/spruce" "grout/cfw/trimui" @@ -40,6 +41,8 @@ func GetRomDirectory() string { return batocera.GetRomDirectory() case MinUI: return minui.GetRomDirectory() + case RetroDECK: + return retrodeck.GetRomDirectory() } return "" } @@ -81,6 +84,8 @@ func GetBIOSDirectory() string { return batocera.GetBIOSDirectory() case MinUI: return minui.GetBIOSDirectory() + case RetroDECK: + return retrodeck.GetBIOSDirectory() } return "" } @@ -132,6 +137,8 @@ func GetArtDirectory(romDir string, platformFSSlug, platformName string) string return batocera.GetArtDirectory(romDir) case MinUI: return minui.GetArtDirectory(romDir) + case RetroDECK: + return retrodeck.GetArtDirectory(romDir) default: return "" } @@ -180,6 +187,8 @@ func BaseSavePath() string { return batocera.GetBaseSavePath() case MinUI: return minui.GetBaseSavePath() + case RetroDECK: + return retrodeck.GetBaseSavePath() } return "" } @@ -192,6 +201,8 @@ func GetArtMarqueeDirectory(romDir string, platformFSSlug, platformName string) return knulli.GetArtDirectory(romDir) case Batocera: return batocera.GetArtDirectory(romDir) + case RetroDECK: + return retrodeck.GetArtDirectory(romDir) default: return "" } @@ -205,6 +216,8 @@ func GetArtVideoDirectory(romDir string, platformFSSlug, platformName string) st return knulli.GetVideoDirectory(romDir) case Batocera: return batocera.GetVideoDirectory(romDir) + case RetroDECK: + return retrodeck.GetVideoDirectory(romDir) default: return "" @@ -219,6 +232,8 @@ func GetArtThumbnailDirectory(romDir string, platformFSSlug, platformName string return knulli.GetArtDirectory(romDir) case Batocera: return knulli.GetArtDirectory(romDir) + case RetroDECK: + return retrodeck.GetArtDirectory(romDir) default: return "" } @@ -232,6 +247,8 @@ func GetArtBezelDirectory(romDir string, platformFSSlug, platformName string) st return knulli.GetBezelDirectory(romDir) case Batocera: return batocera.GetBezelDirectory(romDir) + case RetroDECK: + return retrodeck.GetBezelDirectory(romDir) default: return "" } @@ -245,6 +262,8 @@ func GetManualDirectory(romDir string, platformFSSlug, platformName string) stri return knulli.GetManualDirectory(romDir) case Batocera: return batocera.GetManualDirectory(romDir) + case RetroDECK: + return retrodeck.GetManualDirectory(romDir) default: return "" } @@ -258,6 +277,8 @@ func GetBoxbackDirectory(romDir string, platformFSSlug, platformName string) str return knulli.GetArtDirectory(romDir) case Batocera: return batocera.GetArtDirectory(romDir) + case RetroDECK: + return retrodeck.GetArtDirectory(romDir) default: return "" } @@ -271,6 +292,8 @@ func GetFanartDirectory(romDir string, platformFSSlug, platformName string) stri return knulli.GetArtDirectory(romDir) case Batocera: return batocera.GetArtDirectory(romDir) + case RetroDECK: + return retrodeck.GetArtDirectory(romDir) default: return "" } diff --git a/cfw/platforms.go b/cfw/platforms.go index 82a5b41..d9e842c 100644 --- a/cfw/platforms.go +++ b/cfw/platforms.go @@ -9,6 +9,7 @@ import ( "grout/cfw/muos" "grout/cfw/nextui" "grout/cfw/onion" + "grout/cfw/retrodeck" "grout/cfw/rocknix" "grout/cfw/spruce" "grout/cfw/trimui" @@ -33,6 +34,7 @@ func buildPlatformAliasMap() map[string][]string { koriki.Platforms, batocera.Platforms, minui.Platforms, + retrodeck.Platforms, } // Build reverse map: primary folder -> list of RomM slugs that use it as primary @@ -138,6 +140,8 @@ func GetPlatformMap(c CFW) map[string][]string { return batocera.Platforms case MinUI: return minui.Platforms + case RetroDECK: + return retrodeck.Platforms default: return nil } diff --git a/cfw/retrodeck/data/platforms.json b/cfw/retrodeck/data/platforms.json new file mode 100644 index 0000000..06dffdc --- /dev/null +++ b/cfw/retrodeck/data/platforms.json @@ -0,0 +1,407 @@ +{ + "3do": [ + "3do" + ], + "3ds": [ + "n3ds" + ], + "64dd": [ + "n64dd" + ], + "acorn-archimedes": [ + "archimedes" + ], + "acorn-electron": [ + "electron" + ], + "acpc": [ + "amstradcpc" + ], + "amiga": [ + "amiga" + ], + "amiga-cd32": [ + "amigacd32" + ], + "amstrad-gx4000": [ + "gx4000" + ], + "apple-iigs": [ + "apple2gs" + ], + "appleii": [ + "apple2" + ], + "arcade": [ + "arcade" + ], + "arcadia-2001": [ + "arcadia" + ], + "arduboy": [ + "arduboy" + ], + "astrocade": [ + "astrocde" + ], + "atari-st": [ + "atarist" + ], + "atari2600": [ + "atari2600" + ], + "atari5200": [ + "atari5200" + ], + "atari7800": [ + "atari7800" + ], + "atari800": [ + "atari800" + ], + "atari8bit": [ + "atari8bit" + ], + "atari-xegs": [ + "atarixe" + ], + "bbcmicro": [ + "bbcmicro" + ], + "c-plus-4": [ + "plus4" + ], + "c16": [ + "plus4" + ], + "c64": [ + "c64" + ], + "casio-pv-1000": [ + "pv1000" + ], + "colecoadam": [ + "adam" + ], + "colecovision": [ + "colecovision" + ], + "commodore-cdtv": [ + "cdtv" + ], + "creativision": [ + "crvision" + ], + "dc": [ + "dreamcast" + ], + "dos": [ + "dos" + ], + "dragon-32-slash-64": [ + "dragon32" + ], + "epoch-super-cassette-vision": [ + "scv" + ], + "fairchild-channel-f": [ + "channelf" + ], + "famicom": [ + "famicom" + ], + "fds": [ + "fds" + ], + "fm-7": [ + "fm7" + ], + "fm-towns": [ + "fmtowns" + ], + "g-and-w": [ + "gameandwatch" + ], + "gamate": [ + "gamate" + ], + "game-dot-com": [ + "gamecom" + ], + "gamegear": [ + "gamegear" + ], + "gb": [ + "gb" + ], + "gba": [ + "gba" + ], + "gbc": [ + "gbc" + ], + "genesis": [ + "genesis", + "megadrive", + "megadrivejp" + ], + "hartung": [ + "gmaster" + ], + "intellivision": [ + "intellivision" + ], + "j2me": [ + "j2me" + ], + "jaguar": [ + "atarijaguar" + ], + "lynx": [ + "atarilynx" + ], + "mac": [ + "macintosh" + ], + "mega-duck-slash-cougar-boy": [ + "megaduck" + ], + "model2": [ + "model2" + ], + "model3": [ + "model2" + ], + "msx": [ + "msx" + ], + "msx-turbo": [ + "msxturbor" + ], + "msx2": [ + "msx2" + ], + "msx2plus": [ + "msx2plus" + ], + "mugen": [ + "mugen" + ], + "multivision": [ + "multivision" + ], + "n64": [ + "n64" + ], + "nds": [ + "nds" + ], + "neo-geo-cd": [ + "neogeocd", + "neogeocdjp" + ], + "neo-geo-pocket": [ + "ngp" + ], + "neo-geo-pocket-color": [ + "ngpc" + ], + "neogeoaes": [ + "neogeo" + ], + "neogeomvs": [ + "neogeo" + ], + "nes": [ + "nes" + ], + "new-nintendo-3ds": [ + "n3ds" + ], + "ngc": [ + "gc" + ], + "odyssey-2": [ + "odyssey2" + ], + "openbor": [ + "openbor" + ], + "oric": [ + "oric" + ], + "palm-os": [ + "palm" + ], + "pc-8800-series": [ + "pc88" + ], + "pc-9800-series": [ + "pc98" + ], + "pc-booter": [ + "pc" + ], + "pc-engine": [ + "pcengine", + "tg16" + ], + "pc-fx": [ + "pcfx" + ], + "philips-cd-i": [ + "cdimono1" + ], + "pico": [ + "pico8" + ], + "pokemon-mini": [ + "pokemini" + ], + "ps2": [ + "ps2" + ], + "ps3": [ + "ps3" + ], + "psp": [ + "psp" + ], + "psvita": [ + "psvita" + ], + "psx": [ + "psx" + ], + "satellaview": [ + "satellaview" + ], + "saturn": [ + "saturn", + "saturnjp" + ], + "scummvm": [ + "scummvm" + ], + "sega32": [ + "sega32x", + "sega32xjp", + "sega32xna" + ], + "segacd": [ + "segacd" + ], + "sfam": [ + "sfc" + ], + "sg1000": [ + "sg-1000" + ], + "sharp-x68000": [ + "x68000" + ], + "sms": [ + "mastersystem", + "mark3" + ], + "snes": [ + "snes", + "snesna" + ], + "spectravideo": [ + "spectravideo" + ], + "stv": [ + "stv" + ], + "sufami-turbo": [ + "sufami" + ], + "super-acan": [ + "supracan" + ], + "supergrafx": [ + "supergrafx" + ], + "supervision": [ + "supervision" + ], + "switch": [ + "switch" + ], + "tg16": [ + "tg16", + "pcengine" + ], + "thomson-mo5": [ + "moto" + ], + "thomson-to": [ + "moto", + "to8" + ], + "ti-99": [ + "ti99" + ], + "ti-994a": [ + "ti99" + ], + "to8": [ + "to8" + ], + "turbografx-cd": [ + "pcenginecd", + "tg-cd" + ], + "uzebox": [ + "uzebox" + ], + "vectrex": [ + "vectrex" + ], + "vic-20": [ + "vic20" + ], + "virtualboy": [ + "virtualboy" + ], + "vsmile": [ + "vsmile" + ], + "wasm-4": [ + "wasm4" + ], + "wii": [ + "wii" + ], + "wiiu": [ + "wiiu" + ], + "win": [ + "windows9x" + ], + "win3x": [ + "windows3x" + ], + "wonderswan": [ + "wonderswan" + ], + "wonderswan-color": [ + "wonderswancolor" + ], + "x1": [ + "x1" + ], + "xbox": [ + "xbox" + ], + "z-machine": [ + "zmachine" + ], + "zx81": [ + "zx81" + ], + "zxs": [ + "zxspectrum" + ] +} diff --git a/cfw/retrodeck/retrodeck.go b/cfw/retrodeck/retrodeck.go new file mode 100644 index 0000000..20f9a65 --- /dev/null +++ b/cfw/retrodeck/retrodeck.go @@ -0,0 +1,72 @@ +package retrodeck + +import ( + "embed" + "grout/internal/jsonutil" + "os" + "path/filepath" +) + +//go:embed data/*.json +var embeddedFiles embed.FS + +var ( + Platforms = jsonutil.MustLoadJSONMap[string, []string](embeddedFiles, "data/platforms.json") +) + +func GetBasePath() string { + if basePath := os.Getenv("BASE_PATH"); basePath != "" { + return basePath + } + + homeInstall := "/home/deck/retrodeck" + if _, err := os.Stat(homeInstall); err == nil { + return homeInstall + } + + sdcardInstall := "/run/media/mmcblk0p1/retrodeck" + if _, err := os.Stat(sdcardInstall); err == nil { + return sdcardInstall + } + + if homePath := os.Getenv("HOME"); homePath != "" { + customPath := filepath.Join(homePath, "retrodeck") + if _, err := os.Stat(customPath); err == nil { + return customPath + } + } + + return "/retrodeck" +} + +func GetRomDirectory() string { + return filepath.Join(GetBasePath(), "roms") +} + +func GetBIOSDirectory() string { + return filepath.Join(GetBasePath(), "bios") +} + +func GetBaseSavePath() string { + return filepath.Join(GetBasePath(), "saves") +} + +func GetArtDirectory(romDir string) string { + return filepath.Join(romDir, "images") +} + +func GetGroutGamelist() string { + return filepath.Join(GetRomDirectory(), "ports", "gamelist.xml") +} + +func GetVideoDirectory(romDir string) string { + return filepath.Join(romDir, "videos") +} + +func GetBezelDirectory(romDir string) string { + return filepath.Join(romDir, "bezels") +} + +func GetManualDirectory(romDir string) string { + return filepath.Join(romDir, "manuals") +} diff --git a/cfw/saves.go b/cfw/saves.go index 4b1d79c..d3c7553 100644 --- a/cfw/saves.go +++ b/cfw/saves.go @@ -9,6 +9,7 @@ import ( "grout/cfw/muos" "grout/cfw/nextui" "grout/cfw/onion" + "grout/cfw/retrodeck" "grout/cfw/rocknix" "grout/cfw/spruce" "grout/cfw/trimui" @@ -40,6 +41,8 @@ func EmulatorFolderMap(c CFW) map[string][]string { return batocera.Platforms case MinUI: return minui.SaveDirectories + case RetroDECK: + return retrodeck.Platforms default: return nil } diff --git a/docs/_includes/cfw-links.md b/docs/_includes/cfw-links.md index 1fbdf27..2ec13cb 100644 --- a/docs/_includes/cfw-links.md +++ b/docs/_includes/cfw-links.md @@ -11,3 +11,4 @@ [sprigui]: https://github.com/spruceUI/sprigUI [twigui]: https://github.com/spruceUI/twigUI [trimui]: https://github.com/trimui +[retrodeck]: https://retrodeck.net diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 3751d96..733644f 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -27,6 +27,7 @@ Choose your platform: - [ROCKNIX Installation](install-rocknix.md) - [Spruce Installation](install-spruce.md) - [TrimUI Installation](install-trimui.md) +- [RetroDECK Installation](install-retrodeck.md) ### Step 2: Launch and Select Language diff --git a/docs/getting-started/install-retrodeck.md b/docs/getting-started/install-retrodeck.md new file mode 100644 index 0000000..361b544 --- /dev/null +++ b/docs/getting-started/install-retrodeck.md @@ -0,0 +1,67 @@ +# Installation Guide for RetroDECK + +This guide will help you install Grout on devices running [RetroDECK][retrodeck]. + +## Tested Devices + +Grout has been tested on the following devices having RetroDECK installed: + +| Manufacturer | Device | OS | +|--------------|----------|---------| +| Asus | ROG Ally | Bazzite | + +_Please help verify compatibility on other devices by reporting your results!_ + +## Installation Steps + +### Automatic (Recommended) + +Here is an all-in-one install script that will install Grout and add it as a non-Steam game. + +```bash +curl -o- https://raw.githubusercontent.com/rommapp/grout/refs/heads/main/scripts/RetroDECK/install.sh | bash +``` + +```bash +wget -qO- https://raw.githubusercontent.com/rommapp/grout/refs/heads/main/scripts/RetroDECK/install.sh | bash +``` + +### Manual + +1. Ensure your device has RetroDECK installed. +2. Download the [latest Grout release](https://github.com/rommapp/grout/releases/latest/download/Grout-RetroDECK.zip) for + RetroDECK. +3. Unzip the downloaded archive. +4. Copy the `Grout` folder to your home directory (`/home/deck/grout/`) +5. Copy the `Grout.sh` file to the same Ports directory (`/home/deck/grout/Grout.sh`) +6. Open Steam and add Grout as a non-Steam game: + - Target: `env` + - Start In: `/home/deck/grout/` + - Launch options: `/home/deck/grout/Grout.sh` + - You'll find game media in `/home/deck/grout/Grout/media/` +7. Launch Grout from Steam and enjoy! + +## Update + +### In-App update (Recommended) + +Grout has a built-in update mechanism. To update Grout, launch the application and navigate to the `Settings` menu. From there, +select `Check for Updates`. If a new version is available, follow the on-screen prompts to download and install the update. + +### Manual update + +To update Grout, simply download the latest release and replace the existing Grout folder in your home directory (`/home/deck/grout/`). If you +have made any custom configurations, ensure to back them up before replacing the folder. Be sure to keep the `config.json` +file if you do not want to authenticate again, and configure platforms folder mappings again. + +## Additional Notes + +- Grout doesn't currently support custom RetroDECK install location: you must have selected either the internal or the SD card install. +- It seems like Grout doesn't currently play well with Steam Input, ensure it is disabled or you're using an external controller. +- Given the above and if you're running Bazzite, you may need to configure your handheld so it's seen as an Xbox controller. + +## Next Steps + +After installation is complete, check out the [User Guide](../usage/guide.md) to learn how to use Grout. + +--8<-- "docs/_includes/cfw-links.md" diff --git a/docs/index.md b/docs/index.md index 4be37f8..678a3df 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,7 +13,7 @@ hide: Download and manage games from your [RomM](https://romm.app) instance directly on your Linux based retro handheld. -[Allium](getting-started/install-allium.md) · [Batocera](getting-started/install-batocera.md) · [Knulli](getting-started/install-knulli.md) · [MinUI](getting-started/install-minui.md) · [muOS](getting-started/install-muos.md) · [NextUI](getting-started/install-nextui.md) · [Onion](getting-started/install-onion.md) · [ROCKNIX](getting-started/install-rocknix.md) · [Spruce](getting-started/install-spruce.md) · [TrimUI](getting-started/install-trimui.md) +[Allium](getting-started/install-allium.md) · [Batocera](getting-started/install-batocera.md) · [Knulli](getting-started/install-knulli.md) · [MinUI](getting-started/install-minui.md) · [muOS](getting-started/install-muos.md) · [NextUI](getting-started/install-nextui.md) · [Onion](getting-started/install-onion.md) · [ROCKNIX](getting-started/install-rocknix.md) · [Spruce](getting-started/install-spruce.md) · [TrimUI](getting-started/install-trimui.md) · [RetroDECK](getting-started/install-retrodeck.md) [:fontawesome-solid-gamepad: Get Started](getting-started/index.md){ .md-button .md-button--primary }    diff --git a/docs/platforms/RETRODECK.md b/docs/platforms/RETRODECK.md new file mode 100644 index 0000000..5bc7c8a --- /dev/null +++ b/docs/platforms/RETRODECK.md @@ -0,0 +1,132 @@ +# RetroDECK Platform Mappings + +This table shows the mappings of RomM Fs Slug to RetroDECK's platform folders. + +| Platform Name | RomM Fs Slug | Folder(s) | +|----------------------------------|-----------------------------|---------------------------------| +| 3DO Interactive Multiplayer | 3do | 3do | +| Acorn Archimedes | acorn-archimedes | archimedes | +| Acorn Computers BBC Micro | bbcmicro | bbcmicro | +| Acorn Electron | acorn-electron | electron | +| Amstrad CPC | acpc | amstradcpc | +| Amstrad GX4000 | amstrad-gx4000 | gx4000 | +| Apple II | appleii | apple2 | +| Apple IIGS | apple-iigs | apple2gs | +| Apple Macintosh | mac | macintosh | +| Arcade | arcade | arcade | +| Arduboy Miniature Game System | arduboy | arduboy | +| Atari 2600 | atari2600 | atari2600 | +| Atari 5200 | atari5200 | atari5200 | +| Atari 7800 ProSystem | atari7800 | atari7800 | +| Atari 800 | atari800 | atari800 | +| Atari Jaguar | jaguar | atarijaguar | +| Atari Lynx | lynx | atarilynx | +| Atari ST | atari-st | atarist | +| Atari XE | atari-xegs | atarixe | +| Bally Astrocade | astrocade | astrocde | +| Bandai SuFami Turbo | sufami-turbo | sufami | +| Bandai WonderSwan | wonderswan | wonderswan | +| Bandai WonderSwan Color | wonderswan-color | wonderswancolor | +| Bit Corporation Gamate | gamate | gamate | +| Casio PV-1000 | casio-pv-1000 | pv1000 | +| Coleco Adam | colecoadam | adam | +| Coleco ColecoVision | colecovision | colecovision | +| Commodore 64 | c64 | c64 | +| Commodore Amiga | amiga | amiga | +| Commodore Amiga CD32 | amiga-cd32 | amigacd32 | +| Commodore CDTV | commodore-cdtv | cdtv | +| Commodore Plus/4 | c-plus-4, c16 | plus4 | +| Commodore VIC-20 | vic-20 | vic20 | +| Creatronic Mega Duck | mega-duck-slash-cougar-boy | megaduck | +| DOS (PC) | dos | dos | +| Dragon Data Dragon 32 | dragon-32-slash-64 | dragon32 | +| Emerson Arcadia 2001 | arcadia-2001 | arcadia | +| Epoch Super Cassette Vision | epoch-super-cassette-vision | scv | +| Fairchild Channel F | fairchild-channel-f | channelf | +| Fujitsu FM Towns | fm-towns | fmtowns | +| Fujitsu FM-7 | fm-7 | fm7 | +| Funtech Super A'Can | super-acan | supracan | +| GCE Vectrex | vectrex | vectrex | +| Hartung Game Master | hartung | gmaster | +| IBM PC | pc-booter | pc | +| Infocom Z-machine | z-machine | zmachine | +| Java 2 Micro Edition (J2ME) | j2me | j2me | +| M.U.G.E.N Game Engine | mugen | mugen | +| Magnavox Odyssey 2 | odyssey-2 | odyssey2 | +| Mattel Electronics Intellivision | intellivision | intellivision | +| Microsoft Windows 3.x | win3x | windows3x | +| Microsoft Windows 9x | win | windows9x | +| Microsoft Xbox | xbox | xbox | +| MSX | msx | msx | +| MSX Turbo R | msx-turbo | msxturbor | +| MSX2 | msx2 | msx2 | +| NEC PC Engine | pc-engine | pcengine, tg16 | +| NEC PC Engine CD | turbografx-cd | pcenginecd, tg-cd | +| NEC PC-8800 Series | pc-8800-series | pc88 | +| NEC PC-9800 Series | pc-9800-series | pc98 | +| NEC PC-FX | pc-fx | pcfx | +| NEC SuperGrafx | supergrafx | supergrafx | +| NEC TurboGrafx-16 | tg16 | tg16, pcengine | +| Nintendo 3DS | 3ds, new-nintendo-3ds | n3ds | +| Nintendo 64 | n64 | n64 | +| Nintendo 64DD | 64dd | n64dd | +| Nintendo DS | nds | nds | +| Nintendo Entertainment System | nes | nes | +| Nintendo Famicom Disk System | fds | fds | +| Nintendo Family Computer | famicom | famicom | +| Nintendo Game and Watch | g-and-w | gameandwatch | +| Nintendo Game Boy | gb | gb | +| Nintendo Game Boy Advance | gba | gba | +| Nintendo Game Boy Color | gbc | gbc | +| Nintendo GameCube | ngc | gc | +| Nintendo Pokémon Mini | pokemon-mini | pokemini | +| Nintendo Satellaview | satellaview | satellaview | +| Nintendo SFC (Super Famicom) | sfam | sfc | +| Nintendo SNES (Super Nintendo) | snes | snes, snesna | +| Nintendo Switch | switch | switch | +| Nintendo Virtual Boy | virtualboy | virtualboy | +| Nintendo Wii | wii | wii | +| Nintendo Wii U | wiiu | wiiu | +| OpenBOR Game Engine | openbor | openbor | +| Othello Multivision | multivision | multivision | +| Palm OS | palm-os | palm | +| Philips CD-i | philips-cd-i | cdimono1 | +| PICO-8 Fantasy Console | pico | pico8 | +| ScummVM Game Engine | scummvm | scummvm | +| Sega CD | segacd | segacd | +| Sega Dreamcast | dc | dreamcast | +| Sega Game Gear | gamegear | gamegear | +| Sega Genesis | genesis | genesis, megadrive, megadrivejp | +| Sega Master System | sms | mastersystem, mark3 | +| Sega Mega Drive 32X | sega32 | sega32x, sega32xjp, sega32xna | +| Sega Model 2 | model2, model3 | model2 | +| Sega Saturn | saturn | saturn, saturnjp | +| Sega SG-1000 | sg1000 | sg-1000 | +| Sega Titan Video Game System | stv | stv | +| Sharp X1 | x1 | x1 | +| Sharp X68000 | sharp-x68000 | x68000 | +| Sinclair ZX Spectrum | zxs | zxspectrum | +| Sinclair ZX81 | zx81 | zx81 | +| SNK Neo Geo | neogeoaes, neogeomvs | neogeo | +| SNK Neo Geo CD | neo-geo-cd | neogeocd, neogeocdjp | +| SNK Neo Geo Pocket | neo-geo-pocket | ngp | +| SNK Neo Geo Pocket Color | neo-geo-pocket-color | ngpc | +| Sony PlayStation | psx | psx | +| Sony PlayStation 2 | ps2 | ps2 | +| Sony PlayStation 3 | ps3 | ps3 | +| Sony PlayStation Portable | psp | psp | +| Sony PlayStation Vita | psvita | psvita | +| Spectravideo | spectravideo | spectravideo | +| Tangerine Computer Systems Oric | oric | oric | +| Texas Instruments TI-99 | ti-99, ti-994a | ti99 | +| Thomson MO/TO Series | thomson-mo5 | moto | +| Thomson MO/TO Series | thomson-to | moto, to8 | +| Thomson TO8 | to8 | to8 | +| Tiger Electronics Game.com | game-dot-com | gamecom | +| Unknown | atari8bit | atari8bit | +| Unknown | msx2plus | msx2plus | +| Uzebox Open Source Console | uzebox | uzebox | +| VTech CreatiVision | creativision | crvision | +| VTech V.Smile | vsmile | vsmile | +| WASM-4 Fantasy Console | wasm-4 | wasm4 | +| Watara Supervision | supervision | supervision | \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 8377774..a0e8460 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,6 +77,7 @@ nav: - ROCKNIX: getting-started/install-rocknix.md - Spruce: getting-started/install-spruce.md - TrimUI: getting-started/install-trimui.md + - RetroDECK: getting-started/install-retrodeck.md - Usage: - User Guide: usage/guide.md - Settings Reference: usage/settings.md @@ -93,6 +94,7 @@ nav: - ROCKNIX: platforms/rocknix.md - Spruce: platforms/spruce.md - TrimUI: platforms/trimui.md + - RetroDECK: platforms/RETRODECK.md - Contributing: - contributing/index.md - Development Guide: contributing/development.md diff --git a/scripts/RetroDECK/Grout.sh b/scripts/RetroDECK/Grout.sh new file mode 100644 index 0000000..1ec0423 --- /dev/null +++ b/scripts/RetroDECK/Grout.sh @@ -0,0 +1,16 @@ +#!/bin/bash +CUR_DIR="$(realpath "$(dirname "$0")")" +cd "$CUR_DIR/Grout" || exit 1 + +# Apply pending update +if [ -d "../.update" ]; then + cp -rf ../.update/* .. + rm -rf ../.update +fi + +export CFW=RETRODECK +export LD_LIBRARY_PATH="$CUR_DIR/Grout/lib:$LD_LIBRARY_PATH" + +./grout + +exit 0 diff --git a/scripts/RetroDECK/install.sh b/scripts/RetroDECK/install.sh new file mode 100644 index 0000000..352e06f --- /dev/null +++ b/scripts/RetroDECK/install.sh @@ -0,0 +1,38 @@ +GROUT_VERSION=4.8.1.0 +GROUT_URL=https://github.com/rommapp/grout/releases/download/v$GROUT_VERSION/Grout-RetroDECK.zip + +NONSTEAM_VERSION=0.7.0 +NONSTEAM_URL=https://github.com/cameronhimself/nonsteam/releases/download/$NONSTEAM_VERSION/nonsteam-linux-x64-$NONSTEAM_VERSION.tar.gz + +echo "Creating installation directory..." +mkdir -p "$HOME/grout" && cd "$HOME/grout" +export PATH="$HOME/grout:$PATH" + +echo "Downloading and extracting Grout..." +curl -sL -o grout.zip $GROUT_URL +unzip -d . -o -qq grout.zip +chmod +x Grout.sh Grout/grout +rm grout.zip + +echo "Downloading and extracting nonsteam..." +curl -sL -o nonsteam.tgz $NONSTEAM_URL +tar -xzf nonsteam.tgz --strip-components=1 +rm nonsteam.tgz + +echo "Adding Grout as a non-Steam game..." +nonsteam add -w \ + --app-name "Grout" \ + --exe "env" \ + --start-dir "$HOME/grout/" \ + --launch-options "$HOME/grout/Grout.sh" \ + --image-icon "$HOME/grout/Grout/media/icon.png" \ + --image-grid "$HOME/grout/Grout/media/cover.png" \ + --image-grid-horiz "$HOME/grout/Grout/media/banner.png" \ + --image-hero "$HOME/grout/Grout/media/background.png" \ + --image-logo "$HOME/grout/Grout/media/logo.png" \ + --allow-overlay + +echo "Cleaning up..." +rm nonsteam + +echo "Done! Please restart Steam for changes to take effect." diff --git a/scripts/RetroDECK/media/background.png b/scripts/RetroDECK/media/background.png new file mode 100644 index 0000000..2f5d5a1 Binary files /dev/null and b/scripts/RetroDECK/media/background.png differ diff --git a/scripts/RetroDECK/media/banner.png b/scripts/RetroDECK/media/banner.png new file mode 100644 index 0000000..2e89752 Binary files /dev/null and b/scripts/RetroDECK/media/banner.png differ diff --git a/scripts/RetroDECK/media/cover.png b/scripts/RetroDECK/media/cover.png new file mode 100644 index 0000000..b50ac77 Binary files /dev/null and b/scripts/RetroDECK/media/cover.png differ diff --git a/scripts/RetroDECK/media/icon.png b/scripts/RetroDECK/media/icon.png new file mode 100644 index 0000000..808cfcb Binary files /dev/null and b/scripts/RetroDECK/media/icon.png differ diff --git a/scripts/RetroDECK/media/logo.png b/scripts/RetroDECK/media/logo.png new file mode 100644 index 0000000..b04ce27 Binary files /dev/null and b/scripts/RetroDECK/media/logo.png differ diff --git a/taskfiles/build.yml b/taskfiles/build.yml index e875d1f..0937a0e 100644 --- a/taskfiles/build.yml +++ b/taskfiles/build.yml @@ -22,7 +22,8 @@ tasks: - docker create --name {{.CONTAINER_NAME}}-{{.BUILD_DIR}} --label {{.LABEL}} {{.IMAGE_TAG}} >/dev/null 2>&1 - echo "Extracting {{.BUILD_DIR}}..." - docker cp {{.CONTAINER_NAME}}-{{.BUILD_DIR}}:/build/grout {{.BUILD_DIR}}/grout - - 'if [ -n "{{.LIB_PATH}}" ]; then docker cp {{.CONTAINER_NAME}}-{{.BUILD_DIR}}:{{.LIB_PATH}} {{.BUILD_DIR}}/lib/libSDL2_gfx-1.0.so.0; fi' + - for: { var: LIBS } + cmd: docker cp -L {{.CONTAINER_NAME}}-{{.BUILD_DIR}}:{{.LIBS_PATH}}{{.ITEM}} {{.BUILD_DIR}}/lib/ - docker rm {{.CONTAINER_NAME}}-{{.BUILD_DIR}} >/dev/null 2>&1 - docker image prune --filter "label={{.LABEL}}" -f >/dev/null 2>&1 || true - echo "Extract {{.BUILD_DIR}} complete" @@ -35,7 +36,16 @@ tasks: - task: _build vars: { PLATFORM: linux/arm64, BUILD_DIR: build64, IMAGE_TAG: "{{.IMAGE_NAME}}-arm64", DOCKERFILE: docker/Dockerfile, LOCAL: "{{.LOCAL}}" } - task: _extract - vars: { BUILD_DIR: build64, IMAGE_TAG: "{{.IMAGE_NAME}}-arm64", LIB_PATH: /usr/lib/aarch64-linux-gnu/libSDL2_gfx-1.0.so.0.0.2 } + vars: { BUILD_DIR: build, IMAGE_TAG: "{{.IMAGE_NAME}}-amd64", LIBS_PATH: "/usr/lib/aarch64-linux-gnu/", LIBS: [ + "libSDL2-2.0.so.0", + "libSDL2_image-2.0.so.0", + "libSDL2_gfx-1.0.so.0", + "libSDL2_ttf-2.0.so.0", + "libjpeg.so.62", + "libtiff.so.5", + "libwebp.so.6", + "libjbig.so.0" + ],} amd64: desc: Build and extract for AMD64 (x86_64) @@ -43,7 +53,16 @@ tasks: - task: _build vars: { PLATFORM: linux/amd64, BUILD_DIR: build, IMAGE_TAG: "{{.IMAGE_NAME}}-amd64", DOCKERFILE: docker/Dockerfile } - task: _extract - vars: { BUILD_DIR: build, IMAGE_TAG: "{{.IMAGE_NAME}}-amd64", LIB_PATH: /usr/lib/x86_64-linux-gnu/libSDL2_gfx-1.0.so.0.0.2 } + vars: { BUILD_DIR: build, IMAGE_TAG: "{{.IMAGE_NAME}}-amd64", LIBS_PATH: "/usr/lib/x86_64-linux-gnu/", LIBS: [ + "libSDL2-2.0.so.0", + "libSDL2_image-2.0.so.0", + "libSDL2_gfx-1.0.so.0", + "libSDL2_ttf-2.0.so.0", + "libjpeg.so.62", + "libtiff.so.5", + "libwebp.so.6", + "libjbig.so.0" + ],} x86: desc: Build and extract for x86 (32-bit) @@ -51,7 +70,16 @@ tasks: - task: _build vars: { PLATFORM: linux/386, BUILD_DIR: buildx86, IMAGE_TAG: "{{.IMAGE_NAME}}-x86", DOCKERFILE: docker/Dockerfile } - task: _extract - vars: { BUILD_DIR: buildx86, IMAGE_TAG: "{{.IMAGE_NAME}}-x86", LIB_PATH: /usr/lib/i386-linux-gnu/libSDL2_gfx-1.0.so.0.0.2 } + vars: { BUILD_DIR: build, IMAGE_TAG: "{{.IMAGE_NAME}}-amd64", LIBS_PATH: "/usr/lib/i386-linux-gnu/", LIBS: [ + "libSDL2-2.0.so.0", + "libSDL2_image-2.0.so.0", + "libSDL2_gfx-1.0.so.0", + "libSDL2_ttf-2.0.so.0", + "libjpeg.so.62", + "libtiff.so.5", + "libwebp.so.6", + "libjbig.so.0" + ],} arm32: desc: Build and extract for ARM32 @@ -60,6 +88,6 @@ tasks: cmds: - task: _build vars: { PLATFORM: linux/arm/v7, BUILD_DIR: build32, IMAGE_TAG: "{{.IMAGE_NAME}}-arm32", DOCKERFILE: docker/32.Dockerfile, LOCAL: "{{.LOCAL}}" } - # TODO: add LIB_PATH once custom SDL build for Miyoo is ready + # TODO: add LIBS and LIBS_PATH once custom SDL build for Miyoo is ready - task: _extract - vars: { BUILD_DIR: build32, IMAGE_TAG: "{{.IMAGE_NAME}}-arm32", LIB_PATH: "" } + vars: { BUILD_DIR: build32, IMAGE_TAG: "{{.IMAGE_NAME}}-arm32", LIBS: [], LIBS_PATH: "" } diff --git a/taskfiles/package.yml b/taskfiles/package.yml index 9007c44..fde34c6 100644 --- a/taskfiles/package.yml +++ b/taskfiles/package.yml @@ -147,3 +147,14 @@ tasks: - cp -R build/lib/* dist/Batocera-amd64/Grout/lib/ - chmod a+x dist/Batocera-amd64/Grout/grout dist/Batocera-amd64/Grout.sh silent: true + + retrodeck: + cmds: + - rm -rf dist/RetroDECK + - mkdir -p dist/RetroDECK/Grout/{lib,media} + - cp scripts/RetroDECK/Grout.sh dist/RetroDECK/ + - cp scripts/RetroDECK/media/* dist/RetroDECK/Grout/media/ + - cp build/grout README.md LICENSE dist/RetroDECK/Grout/ + - cp -R build/lib/* dist/RetroDECK/Grout/lib/ + - chmod a+x dist/RetroDECK/Grout/grout dist/RetroDECK/Grout.sh + silent: true diff --git a/ui/games_list.go b/ui/games_list.go index 3cd0af5..79aeb2b 100644 --- a/ui/games_list.go +++ b/ui/games_list.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "grout/cache" + "grout/cfw" "grout/internal" "grout/internal/environment" "grout/internal/stringutil" @@ -260,7 +261,11 @@ func (s *GameListScreen) Draw(input GameListInput) (GameListOutput, error) { options.SecondaryActionButton = gabaconst.VirtualButtonY if hasBIOS && !internal.IsKidModeEnabled() { - options.TertiaryActionButton = gabaconst.VirtualButtonMenu + if environment.IsMiyoo() || cfw.GetCFW() == cfw.RetroDECK { + options.TertiaryActionButton = gabaconst.VirtualButtonL2 + } else { + options.TertiaryActionButton = gabaconst.VirtualButtonMenu + } } var footerItems []gaba.FooterHelpItem @@ -269,7 +274,7 @@ func (s *GameListScreen) Draw(input GameListInput) (GameListOutput, error) { if hasBIOS && !internal.IsKidModeEnabled() { menuButtonName := i18n.Localize(&goi18n.Message{ID: "button_menu", Other: "Menu"}, nil) - if environment.IsMiyoo() { + if environment.IsMiyoo() || cfw.GetCFW() == cfw.RetroDECK { menuButtonName = "L2" } footerItems = append(footerItems, gaba.FooterHelpItem{ButtonName: menuButtonName, HelpText: i18n.Localize(&goi18n.Message{ID: "button_bios", Other: "BIOS"}, nil)})