mirror of
https://github.com/mihawk-99/PS5_RetroArch.git
synced 2026-10-18 23:09:29 -05:00
Sets up this project as the native pipeline's scaffolding plus RetroArch's
sources, so RetroArch is compiled for the title pipeline rather than converted
into it.
- tools/scaffold-native.sh builds the scaffold from
../ps5-native-app-boilerplate-main: tooling, runtime (digest verified),
Makefile and its tools, merged into this repository's tools/ rather than
replacing them. An earlier version replaced tools/ wholesale and deleted this
project's own scripts; the copy is now additive and the reason is in the file.
- tools/fetch-retroarch.sh clones the pinned upstream tag into vendor/ and
records the revision, so "built from RetroArch 1.22.2" is checkable.
- src/display.{hpp,cpp} owns the console's display: VideoOut, direct memory, two
registered buffers, present-and-wait. The sequence and its two load-bearing
details come from the sibling application that proved it on hardware.
- src/main.cpp draws a moving bar: the cheapest thing that proves build, title
format, launcher, VideoOut and the direct-memory path together.
- sce_sys/param.json is this project's identity, PPSA99169.
Evidence: src/display.cpp compiles through the pipeline's compiler
(tooling/prospero-clang18 with PS5_CLANG=/usr/bin/clang, -std=c++20), and a
RetroArch source file compiles the same way with its include paths.
88 lines
2.8 KiB
Bash
88 lines
2.8 KiB
Bash
#!/usr/bin/env bash
|
|
# ps5-native-app-boilerplate - Application identity initializer.
|
|
# Copyright (C) 2026 BlackBearReloaded
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
# Updates the coordinated identity and category fields in param.json.
|
|
|
|
set -euo pipefail
|
|
|
|
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
|
param=${1:-$root/sce_sys/param.json}
|
|
|
|
command -v python3 >/dev/null || {
|
|
echo "missing required command: python3" >&2
|
|
exit 2
|
|
}
|
|
|
|
python3 - "$param" <<'PY'
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import re
|
|
import stat
|
|
import sys
|
|
import tempfile
|
|
|
|
path = Path(sys.argv[1])
|
|
title_id = os.environ.get("TITLE_ID", "")
|
|
app_name = os.environ.get("APP_NAME", "").strip()
|
|
category = os.environ.get("APP_CATEGORY", "game").lower()
|
|
suffix = os.environ.get("CONTENT_SUFFIX", "")
|
|
|
|
if not re.fullmatch(r"PPSA\d{5}", title_id):
|
|
raise SystemExit("TITLE_ID must use PPSA followed by five digits")
|
|
if not app_name or any(character in app_name for character in "\r\n"):
|
|
raise SystemExit("APP_NAME must be a non-empty, single-line title")
|
|
if category not in {"game", "media"}:
|
|
raise SystemExit("APP_CATEGORY must be game or media")
|
|
if not suffix:
|
|
suffix = re.sub(r"[^A-Z0-9]", "", app_name.upper())[:16].ljust(16, "0")
|
|
if not re.fullmatch(r"[A-Z0-9]{16}", suffix):
|
|
raise SystemExit("CONTENT_SUFFIX must contain exactly 16 uppercase letters or digits")
|
|
|
|
with path.open(encoding="utf-8") as source:
|
|
param = json.load(source)
|
|
original_mode = stat.S_IMODE(path.stat().st_mode)
|
|
|
|
content_id = param.get("contentId", "")
|
|
prefix = content_id.split("-", 1)[0]
|
|
if not re.fullmatch(r"[A-Z]{2}\d{4}", prefix):
|
|
prefix = "UP9000"
|
|
|
|
param["titleId"] = title_id
|
|
param["conceptId"] = title_id[4:]
|
|
param["contentId"] = f"{prefix}-{title_id}_00-{suffix}"
|
|
|
|
localized = param.setdefault("localizedParameters", {})
|
|
language = localized.setdefault("defaultLanguage", "en-US")
|
|
localized.setdefault(language, {})["titleName"] = app_name
|
|
|
|
if category == "game":
|
|
param["applicationCategoryType"] = 0
|
|
param["contentBadgeType"] = 1
|
|
param["gameIntent"] = {"permittedIntents": [{"intentType": "launchActivity"}]}
|
|
else:
|
|
param["applicationCategoryType"] = 65536
|
|
param["contentBadgeType"] = 2
|
|
param.pop("gameIntent", None)
|
|
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
descriptor, temporary_name = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent)
|
|
try:
|
|
with os.fdopen(descriptor, "w", encoding="utf-8", newline="\n") as output:
|
|
json.dump(param, output, indent=2, ensure_ascii=False)
|
|
output.write("\n")
|
|
os.chmod(temporary_name, original_mode)
|
|
os.replace(temporary_name, path)
|
|
except BaseException:
|
|
try:
|
|
os.unlink(temporary_name)
|
|
except FileNotFoundError:
|
|
pass
|
|
raise
|
|
|
|
print(f"Configured {title_id}: {app_name} ({category})")
|
|
print(f"Content ID: {param['contentId']}")
|
|
PY
|