Package: list the app under Applications, not Games

The package declared itself a game (CATEGORY gd), so the PS4 filed it under
Games in the library.

It now uses the values Apollo Save Tool ships with: CATEGORY gde ("Non-Game Mini
App"), ATTRIBUTE 32, APP_TYPE 1. Apollo is built with the same OpenOrbis tools and
lists under Applications. APP_TYPE 4 ("Freemium"), which is reported to move apps
there too, made the PS4 refuse to start ours (CE-39929-2), so it stays 1.

Confirmed on the console (firmware 10.01): the app installs, starts, and lists
under Library > Applications. A test reads the fields back out of the built
package.
This commit is contained in:
MoHadiShibli committed 2026-10-05 15:30:36 +03:00
1 parent ffe5615da3
commit a039ce9532
2 files changed
+29 -1

No files matched your search

+23
View File
@@ -4,6 +4,7 @@ import os
from pathlib import Path
import re
import socket
import struct
import subprocess
import sys
import tempfile
@@ -195,6 +196,28 @@ def main():
assert not found, 'OpenOrbis Linux-valued constant used directly:\n' + '\n'.join(found)
print('PASS no OpenOrbis constant with a Linux value is used directly', flush=True)
# The package's param.sfo, as the PS4 reads it (built by `make -C launcher`).
sfo = ROOT / 'build/launcher/pkg/sce_sys/param.sfo'
if not sfo.exists():
print('SKIP param.sfo checks: build the package first (make -C launcher)', flush=True)
return
data = sfo.read_bytes()
magic, _, keys, values, count = struct.unpack_from('<4sIIII', data)
assert magic == b'\0PSF', magic
fields = {}
for i in range(count):
key_at, kind, length, _, value_at = struct.unpack_from('<HHIII', data, 20 + 16 * i)
name = data[keys + key_at:data.index(b'\0', keys + key_at)].decode()
raw = data[values + value_at:values + value_at + length]
fields[name] = struct.unpack('<I', raw)[0] if kind == 0x0404 else raw.rstrip(b'\0').decode()
version = (ROOT / 'VERSION').read_text().strip()
major, minor = version.split('.')[:2]
# Listed under Applications rather than Games, as Apollo Save Tool is.
assert (fields['CATEGORY'], fields['APP_TYPE'], fields['ATTRIBUTE']) == ('gde', 1, 32), fields
assert fields['TITLE_ID'] == 'CFRE00001' and fields['TITLE'] == 'Control4Free', fields
assert fields['APP_VER'] == fields['VERSION'] == f'{int(major):02d}.{int(minor):02d}', fields
print('PASS param.sfo: an application, its title, and the version from VERSION', flush=True)
if __name__ == '__main__':
main()
+6 -1
View File
@@ -127,9 +127,14 @@ def main():
pkgtool = binary / 'PkgTool.Core'
sfo = 'sce_sys/param.sfo'
run(pkgtool, 'sfo_new', sfo)
# Listed under Applications, not Games: the values Apollo Save Tool ships with
# (bucanero/apollo-ps4, built with the same OpenOrbis tools), which lists there
# and starts fine. CATEGORY gde is "Non-Game Mini App"; gd, which we had, is
# "Game Digital Application". APP_TYPE must stay 1: with 4 ("Freemium") the PS4
# refused to start the app (CE-39929-2, firmware 10.01, 2026-10-05).
entries = {
'APP_TYPE': ('Integer', 4, '1'), 'APP_VER': ('Utf8', 8, SFO_VERSION),
'ATTRIBUTE': ('Integer', 4, '0'), 'CATEGORY': ('Utf8', 4, 'gd'),
'ATTRIBUTE': ('Integer', 4, '32'), 'CATEGORY': ('Utf8', 4, 'gde'),
'CONTENT_ID': ('Utf8', 48, CONTENT_ID), 'DOWNLOAD_DATA_SIZE': ('Integer', 4, '0'),
'SYSTEM_VER': ('Integer', 4, '0'), 'TITLE': ('Utf8', 128, 'Control4Free'),
'TITLE_ID': ('Utf8', 12, TITLE_ID), 'VERSION': ('Utf8', 8, SFO_VERSION),