Files
AnyPS5/docs/dev/debt/libSceNpTrophy2.md
T
milescovielloandClaude Opus 5.5 ca34fdb351 feat(libSceNpTrophy2,libSceNpUniversalDataSystem): unlock progressive trophies through _UpdateTrophyProgress
Titles report a progressive trophy's progress with _UpdateTrophyProgress
events. Their udsNN.ucp rules feed $._trophy_progress into an int32
statistic with the max aggregation, filtered on $._trophy_id, and the
trophy's unlockCondition names that statistic. Those statistics and
rules were skipped and the events were dropped, so such trophies never
reported progress or unlocked (21 of Borderlands 4's 64).

- Read max statistics (largest value posted, from initialValue) and
  int32 statistics (0 to 2147483647).
- Read a rule condition with one == property equal to an unsigned
  integer, and apply the rule only to events whose property matches.
- Post _UpdateTrophyProgress through the statistic rules.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 17:24:43 +01:00

6.5 KiB

libSceNpTrophy2 technical debt

Silent stubs

  • sceNpTrophy2GetRewardIcon (libSceNpTrophy2) - zeroes size and returns SCE_NP_TROPHY2_ERROR_ICON_FILE_NOT_FOUND (-2141898479): the (int context, int handle, int reward_id, void* buffer, size_t* size) signature and two-stage query pattern follow the bundled Media/Plugins/PSNCore.prx of PPSA06888 and SharpProspero; returning -2141898479 (0x80553911) when icons are unavailable is inferred from sibling calls (sceNpTrophy2GetGameIcon, sceNpTrophy2GetGroupIcon, sceNpTrophy2GetTrophyIcon) in KytyPS5 (libTrophy.cpp:464/483/502)
  • libSceNpTrophy2: sceNpTrophy2RegisterUnlockCallback accepts a callback that is never called, as the callback's signature and when the console calls it are not known, sceNpTrophy2UnregisterUnlockCallback only returns success, and sceNpTrophy2ShowTrophyList returns success without showing a list (there is no system trophy UI; seen on PPSA15552).

Unknown function info

  • Query structures: a progress value is a 16-byte {int32 type, 4 reserved bytes, uint64 value} and the game, group and trophy structures are 152, 24, 152, 32, 1312 and 32 bytes, as KytyPS5 asserts; no other public source confirms the layout. Progress type 1 marks a progressive trophy's target and progress, as in KytyPS5. Trophies without a groupId belong to group -1, KytyPS5's base game group.

  • libSceNpTrophy2 pending exports - 23 named callable exports were identified in the PS5 3.20 export table and cross-checked against firmware 13.60. Signatures and behavior remain unverified; declarations use the unknown-signature convention and throw through NotImplemented_nid_no_patch. Evidence: 3.20 export list.

Functional

  • Trophy queries - not confirmed on the console: sceNpTrophy2GetTrophyInfo of a trophy id that is not in the title's trophy data (sce_sys/trophy2/trophyNN.ucp) returns 0x8055390A (KytyPS5's NP_TROPHY2_ERROR_INVALID_TROPHY_ID) and writes nothing; a context not created or destroyed reports placeholders and no unlocks and returns success; hidden trophies report their names and descriptions before the unlock; progress_percentage weighs gold 6, silver 2 and bronze 1 and leaves the platinum out, as KytyPS5 does (the ratio of the published PSN trophy points). A group that is not in the data throws. Without the file, or when it is malformed, the queries report the old placeholders and sceNpTrophy2GetTrophyInfoArray lists only trophy 0. Icons are not read. Unlocks come from the trophy store.
  • Trophy data limits: a trophyNN.ucp or udsNN.ucp larger than 256 MiB or listing more than 4096 files, and a JSON file in it that nests deeper than 64 levels or holds more than 1048576 values, are not used, and the title runs as without that file. The limits keep the memory the reader takes to the file and about 140 MiB of parsed JSON; the console's limits are not known.
  • Text language: texts come from tropmeta_<tag>.json for the console language, then en-US, then the file's defaultLanguage. The tags for languages 0 to 29 are KytyPS5's; uk-UA for 30 (Ukrainian) is an assumption.
  • Trophy progress statistics: max (the largest value posted, starting from initialValue, or minValue without one), int32 (0 to 2147483647) and a rule condition of an eventName and one property whose comparator is == and value an unsigned integer follow the rules a title ships for its progressive trophies, not a console measurement. Borderlands 4 (PPSA01494) feeds each one's udsStatId from $._trophy_progress of _UpdateTrophyProgress, through an int32 max statistic and a rule on $._trophy_id. latest and the unsigned types follow KytyPS5.
  • Platinum: an unlock through any path unlocks the platinum that the trophy names in platinumTrophyId once every trophy naming that platinum is unlocked, as KytyPS5 does; trophies without platinumTrophyId are not required. With the title's trophy data loaded, a posted _UnlockTrophy of a trophy that is not in the data, of a platinum or of a progressive trophy is not stored and prints a [trophy] ignored line, as KytyPS5 refuses them, so a progressive trophy unlocks only through its statistic; without trophy data any id of 0 or more is stored, including ids the data would make the platinum, a progressive trophy or no trophy, and the platinum is not unlocked when the trophies it needs are. The console's behaviour is not known.
  • Damaged records: a line in _trophy/<user id>_<service label>.txt or .stats.txt that is not a new <id> <value> pair (a blank line, a carriage return, a repeated or negative id, a value that is not a number) makes readRecord throw a std::runtime_error that names the file and the line. Every call that reads that record then throws it instead of returning, which stops the title as any throwing export does, so the title gets no return value; main returned 0 from these calls. The failed read is not kept, so each later call reads the file again and throws again until the file is fixed or deleted. The unlock record is read by sceNpTrophy2GetTrophyInfo, sceNpTrophy2GetTrophyInfoArray and sceNpTrophy2GetGameInfo for a created context, by sceNpTrophy2GetGroupInfo and sceNpTrophy2GetGroupInfoArray when the title's trophy data is loaded, by a sceNpUniversalDataSystemPostEvent of an _UnlockTrophy that the trophy data does not refuse, and by a statistic change when the trophy data is loaded; the stat record by a sceNpUniversalDataSystemPostEvent of an event that a statistics rule copies and by the trophy queries of a progressive trophy with a statistic. What the console does with a damaged record is not known.