PS4 packaging and docs: scripts/build_ps4.sh, pinned runtime, install guide

build_ps4.sh mirrors build_switch.sh: --fetch downloads the pinned LÖVE for
PS4 runtime and checks its SHA-256, --loose packs a plain game.love, --fused
makes gen1recomp-<ver>-ps4.pkg with the runtime's fuse-pkg.sh.
This commit is contained in:
Tomas Morello
2026-09-23 01:13:50 -03:00
parent c073009099
commit f0aefdec1f
7 changed files with 239 additions and 2 deletions
+3 -2
View File
@@ -102,8 +102,9 @@ SHA-1 before creating any game data. FireRed and LeafGreen support is in beta.
**Platform notes:** [Linux](docs/platforms/linux.md),
[iOS](docs/platforms/ios.md), [Xbox Dev Mode](docs/platforms/xbox.md),
[handhelds](docs/platforms/handhelds.md), and
[Nintendo Switch](docs/platforms/switch.md) each have their own install steps.
[handhelds](docs/platforms/handhelds.md),
[Nintendo Switch](docs/platforms/switch.md), and
[PlayStation 4](docs/platforms/ps4.md) each have their own install steps.
**Windows Defender:** it sometimes flags the Windows build with a generic
detection such as `Trojan:Win32/Wacatac!ml` (#621). This is a known false
+1
View File
@@ -20,6 +20,7 @@ editor, and developer setup live on the
- [Xbox Dev Mode](platforms/xbox.md)
- [Handhelds](platforms/handhelds.md)
- [Nintendo Switch](platforms/switch.md)
- [PlayStation 4](platforms/ps4.md)
## Modding
+11
View File
@@ -0,0 +1,11 @@
# PlayStation 4
Homebrew (GoldHEN) build: `gen1recomp-*-ps4.pkg`, the game fused with
[LÖVE for PS4](https://github.com/tomasmorello/love-ps4) (LÖVE 11.5), pinned
like love-nx is for the Switch. PS4 port by
[Tomas Morello](https://github.com/tomasmorello). Tested on hardware with
Red, Blue and Yellow; Gen 2 and Gen 3 are not tested yet.
- Players: [ps4-install.md](../ps4-install.md). Install the `.pkg` from
USB, copy your own legal ROM over FTP into the inbox, Scan again.
- Builders: `scripts/build_ps4.sh --fetch --fused` (see the script header).
+73
View File
@@ -0,0 +1,73 @@
# Install Gen1Recomp on PlayStation 4
Releases that include PS4 support ship `gen1recomp-*-ps4.pkg`: the game and its
runtime in one installable package. Install it, then import your own legal
`.gb` / `.gbc` ROM.
> You need a PS4 that runs homebrew (GoldHEN). This project does not help you
> set that up.
PS4 port by [Tomas Morello](https://github.com/tomasmorello), on
[LÖVE for PS4](https://github.com/tomasmorello/love-ps4) (LÖVE 11.5).
**Tested on real hardware:** Pokemon Red, Blue and Yellow (ROM import, play,
save and load, mods, returning to the launcher). **Not tested yet:** Gold,
Silver, Crystal, FireRed and LeafGreen. They may work; reports are welcome.
## 1. Install the package
1. Open [Releases](https://github.com/bryanthaboi/gen1recomp/releases) and
download `gen1recomp-*-ps4.pkg` (optionally check it against its `.sha256`).
2. Copy it to a USB drive formatted **exFAT** and plug it into the console.
3. **Settings → Debug Settings → Game → Package Installer**, pick the file.
4. Launch **Gen1Recomp** from the home screen.
Updating: install the newer `.pkg` the same way; it installs over the old one.
Saves, imported ROMs and mods live in `/data/love/pokemon-love2d/`, outside the
package. **Do not delete that folder** when updating.
## 2. Import your ROM
The PS4 has no file picker, so the launcher reads an inbox folder, like the
Switch build:
1. Enable GoldHEN's FTP server (GoldHEN menu), port **2121**.
2. With any FTP client, copy your `.gb` / `.gbc` into
`/data/love/pokemon-love2d/imports/`.
3. In the launcher, press **Scan again**.
The other inboxes work the same way (copy over FTP, then **Scan again** in
that screen), all under `/data/love/pokemon-love2d/`:
| What | Folder |
|---|---|
| Mods (`.zip`) | `imports/mods/` |
| Saves (`.sav`) | `imports/saves/<game>/`, e.g. `imports/saves/red/` |
| Custom Carts (`.g1rcart`) | `imports/carts/` |
## 3. Controls
The launcher uses **D-pad focus navigation**: the highlighted option is the
selected one; Cross confirms, Circle goes back. **Triangle** switches to the
virtual cursor and back. In game, the pad maps like on every other platform.
To quit, use the **PS button** and close the application, like any PS4 app.
⚠ **START + SHARE** belongs to GoldHEN (it opens its menu), so the "hold
START + SELECT" force-quit shortcut does not reach the game on PS4.
## 4. Already have LÖVE for PS4?
`scripts/build_ps4.sh --loose` produces a plain `game.love`: copy it to
`/data/love/game.love` and start **LÖVE for PS4** instead of installing the
standalone package.
## Building
```bash
scripts/build_ps4.sh --fetch --fused --version X.Y.Z
```
Needs the OpenOrbis PS4 Toolchain v0.5.4 packaging tools (`OO_PS4_TOOLCHAIN`)
and bash 4+. The runtime is downloaded from a pinned LÖVE for PS4 release and
verified against `scripts/ps4/love-ps4-runtime.sha256`.
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env bash
# PlayStation 4 packaging entry point (homebrew, GoldHEN).
#
# Usage:
# scripts/build_ps4.sh --fetch
# scripts/build_ps4.sh --loose
# scripts/build_ps4.sh --fused [--version X.Y.Z]
# scripts/build_ps4.sh --fetch --fused [--version X.Y.Z]
#
# Modes:
# --fetch Download the pinned LÖVE for PS4 runtime zip into
# .bazinga/love-ps4/<tag>/ and verify SHA-256 against
# scripts/ps4/love-ps4-runtime.sha256.
#
# --loose Pack game.love into dist/ps4/loose/ for players who already have
# the generic "LÖVE for PS4" package installed: they copy it to
# /data/love/game.love over FTP. Does not need the runtime.
#
# --fused Build gen1recomp-<ver>-ps4.pkg: runtime + game.love in one
# installable package (title id GENR00001; its own tile and saves).
# Requires the pin (run --fetch or combine) and the OpenOrbis
# packaging tools: OO_PS4_TOOLCHAIN pointing at an unpacked
# OpenOrbis PS4 Toolchain v0.5.4 (bin/linux or bin/macos with
# PkgTool.Core and create-gp4), plus bash 4+.
#
# The runtime is LÖVE 11.5 for PS4 by Tomas Morello
# (https://github.com/tomasmorello/love-ps4), pinned the way love-nx is pinned
# for the Switch.
#
# Non-goals: installing on a console, FTP uploads, ROM handling.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
WORK="$ROOT/.bazinga/work"
DIST="$ROOT/dist/ps4"
MANIFEST="$ROOT/scripts/ps4/love-ps4-runtime.sha256"
TITLE_ID="${GEN1_PS4_TITLE_ID:-GENR00001}"
FETCH=0; LOOSE=0; FUSED=0
VERSION="$(git -C "$ROOT" rev-parse --short HEAD 2>/dev/null || echo dev)"
say() { printf '\033[1;32m==>\033[0m %s\n' "$*" >&2; }
fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
while [ $# -gt 0 ]; do
case "$1" in
--fetch) FETCH=1; shift ;;
--loose) LOOSE=1; shift ;;
--fused) FUSED=1; shift ;;
--version) VERSION="$2"; shift 2 ;;
-h|--help) sed -n '2,29p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) fail "unknown argument: $1" ;;
esac
done
[ $((FETCH + LOOSE + FUSED)) -gt 0 ] || fail "specify --fetch, --loose and/or --fused (see --help)"
[ $((LOOSE + FUSED)) -le 1 ] || fail "--loose and --fused cannot be combined"
manifest_field() { # manifest_field <key>
local v
v="$(awk -v k="$1" '$1 == k { print $2; exit }' "$MANIFEST")"
[ -n "$v" ] || fail "$MANIFEST has no '$1' entry"
printf '%s' "$v"
}
TAG="$(manifest_field tag)"
ZIP_NAME="love-ps4-${TAG#v}-runtime.zip"
RUNTIME_DIR="$ROOT/.bazinga/love-ps4/$TAG"
ZIP="$RUNTIME_DIR/$ZIP_NAME"
BASE_URL="${GEN1_LOVE_PS4_BASE_URL:-https://github.com/tomasmorello/love-ps4/releases/download/$TAG}"
sha256_of() {
if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}'
else shasum -a 256 "$1" | awk '{print $1}'; fi
}
fetch_runtime() {
local want have
want="$(manifest_field "$ZIP_NAME")"
mkdir -p "$RUNTIME_DIR"
if [ -f "$ZIP" ] && [ "$(sha256_of "$ZIP")" = "$want" ]; then
say "runtime $TAG already fetched"
else
say "downloading $BASE_URL/$ZIP_NAME"
curl -fL --retry 3 --retry-delay 1 -o "$ZIP.part" "$BASE_URL/$ZIP_NAME" \
|| { rm -f "$ZIP.part"; fail "download failed: $BASE_URL/$ZIP_NAME"; }
have="$(sha256_of "$ZIP.part")"
[ "$have" = "$want" ] || { rm -f "$ZIP.part"; fail "SHA-256 mismatch for $ZIP_NAME: got $have, pinned $want"; }
mv "$ZIP.part" "$ZIP"
fi
rm -rf "$RUNTIME_DIR/unpacked"
mkdir -p "$RUNTIME_DIR/unpacked"
(cd "$RUNTIME_DIR/unpacked" && unzip -q "$ZIP")
}
pack_game_love() {
mkdir -p "$WORK"
local love_out="$WORK/game.love"
# pack_love.sh only accepts X.Y.Z; dev builds (a commit hash) stay unstamped.
if printf '%s' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
"$ROOT/scripts/pack_love.sh" --output "$love_out" --listing "$WORK/love-listing.txt" \
--version "$VERSION" >/dev/null
else
"$ROOT/scripts/pack_love.sh" --output "$love_out" --listing "$WORK/love-listing.txt" >/dev/null
fi
printf '%s' "$love_out"
}
# X.Y.Z -> PS4 APP_VER "NN.NN" as (10*X+Y).Z: 0.3.1 -> 03.01, 1.0.0 -> 10.00.
# Monotonic while Y < 10 and Z < 100, so a newer release installs over an older one.
app_ver() {
if printf '%s' "$1" | grep -Eq '^[0-9]+\.[0-9]\.[0-9]{1,2}$'; then
local x y z
IFS=. read -r x y z <<EOF
$1
EOF
printf '%02d.%02d' "$((10 * x + y))" "$z"
else
printf '00.00' # dev builds: always older than any release
fi
}
[ "$FETCH" -eq 1 ] && fetch_runtime
if [ "$LOOSE" -eq 1 ]; then
mkdir -p "$DIST/loose"
cp "$(pack_game_love)" "$DIST/loose/game.love"
say "dist/ps4/loose/game.love -> copy to /data/love/game.love on the console"
fi
if [ "$FUSED" -eq 1 ]; then
[ -f "$ZIP" ] || fail "runtime not fetched: run with --fetch"
[ -d "$RUNTIME_DIR/unpacked" ] || fetch_runtime
[ -n "${OO_PS4_TOOLCHAIN:-}" ] || fail "OO_PS4_TOOLCHAIN is not set (OpenOrbis PS4 Toolchain v0.5.4)"
fuse="$(ls "$RUNTIME_DIR"/unpacked/*/fuse-pkg.sh)"
love="$(pack_game_love)"
icon="$ROOT/scripts/ps4/icon0.png"
[ -f "$icon" ] || icon=""
mkdir -p "$DIST"
"$fuse" --love "$love" --title-id "$TITLE_ID" --title "Gen1Recomp" \
--version "$(app_ver "$VERSION")" --content-label GEN1RECOMP --out-dir "$WORK/ps4-pkg" \
${icon:+--icon "$icon"}
cp "$WORK"/ps4-pkg/IV0000-"$TITLE_ID"_00-*.pkg "$DIST/gen1recomp-$VERSION-ps4.pkg"
(cd "$DIST" && sha256_of "gen1recomp-$VERSION-ps4.pkg" > "gen1recomp-$VERSION-ps4.pkg.sha256")
say "dist/ps4/gen1recomp-$VERSION-ps4.pkg"
fi
Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

+8
View File
@@ -0,0 +1,8 @@
# LÖVE for PS4 — pinned runtime (Tomas Morello)
# https://github.com/tomasmorello/love-ps4/releases
#
# scripts/build_ps4.sh --fetch downloads <zip> from the release <tag> and refuses
# it unless its SHA-256 matches. Bump both lines together.
tag v0.9.3
love-ps4-0.9.3-runtime.zip 8cc66a447738a6772fc79775d7306791fb63542582e420cf08db8cb0420eded7